Browse Source

Fixed most problems; only enabled a few compiled functions again: JIT
should work fine on the other ones as well...

Yentl Van Tendeloo 8 years ago
parent
commit
ef33410933

+ 23 - 20
bootstrap/conformance_scd.alc

@@ -6,7 +6,7 @@ include "modelling.alh"
 
 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])!
+	return value_eq(model["type_mapping"][instance], type)!
 
 Boolean function is_nominal_instance(model : Element, instance : String, type : String):
 	if (bool_not(dict_in(model["metamodel"]["model"], type))):
@@ -17,11 +17,11 @@ Boolean function is_nominal_instance(model : Element, instance : String, type :
 		// type is an edge, but we aren't
 		return False!
 
-	if (bool_not(dict_in_node(model["type_mapping"], model["model"][instance]))):
+	if (bool_not(dict_in(model["type_mapping"], instance))):
 		// doesn't even have a type
 		return False!
 
-	return is_nominal_subtype(model["metamodel"], reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][instance])), type)!
+	return is_nominal_subtype(model["metamodel"], model["type_mapping"][instance], type)!
 
 Boolean function is_nominal_subtype(metamodel : Element, subclass : String, superclass : String):
 	if (element_eq(metamodel["model"][subclass], metamodel["model"][superclass])):
@@ -101,7 +101,6 @@ String function conformance_scd(model : Element):
 	metamodel = model["metamodel"]
 	typing = model["type_mapping"]
 
-
 	// Create dictionary with all associations and allowed cardinalities
 	if (list_len(model["model"]) > 0):
 		cardinalities = precompute_cardinalities(model)
@@ -110,24 +109,22 @@ String function conformance_scd(model : Element):
 		keys = dict_keys(model["model"])
 		while (0 < list_len(keys)):
 			model_name = set_pop(keys)
-			element = model["model"][model_name]
-			type_name = reverseKeyLookup(metamodel["model"], dict_read_node(typing, element))
+			type_name = read_type(model, model_name)
+
+			log("Check " + model_name)
+			log("   : " + type_name)
 
-			if (bool_not(dict_in_node(typing, element))):
+			if (bool_not(dict_in(typing, model_name))):
 				return "Model has no type specified: " + model_info(model, model_name)!
 
-			if (bool_not(set_in_node(metamodel["model"], dict_read_node(typing, element)))):
+			if (bool_not(dict_in(metamodel["model"], typing[model_name]))):
 				return "Type of element not in specified metamodel: " + model_info(model, model_name)!
 
-			// This is true by definition of is_nominal_instance
-			//if (bool_not(is_nominal_instance(model, model_name, type_name))):
-			//	return "Element is not an instance of its specified type: " + model_info(model, model_name)!
-
 			if (is_edge(element)):
 				src_model = reverseKeyLookup(model["model"], read_edge_src(element))
 				dst_model = reverseKeyLookup(model["model"], read_edge_dst(element))
-				src_metamodel = reverseKeyLookup(metamodel["model"], read_edge_src(dict_read_node(typing, element)))
-				dst_metamodel = reverseKeyLookup(metamodel["model"], read_edge_dst(dict_read_node(typing, element)))
+				src_metamodel = reverseKeyLookup(metamodel["model"], read_edge_src(model["model"][typing[model_name]]))
+				dst_metamodel = reverseKeyLookup(metamodel["model"], read_edge_dst(model["model"][typing[model_name]]))
 
 				if (bool_not(is_nominal_instance(model, src_model, src_metamodel))):
 					return "Source of model edge not typed by source of type: " + model_info(model, model_name)!
@@ -144,7 +141,9 @@ String function conformance_scd(model : Element):
 			if (bool_not(dict_in(spo_cache, type_name))):
 				dict_add(spo_cache, type_name, selectPossibleOutgoing(metamodel, type_name, dict_keys(cardinalities)))
 
+			log("Set copy")
 			check_list = set_copy(spo_cache[type_name])
+			log("Done: " + cast_v2s(read_nr_out(check_list)))
 			while (0 < list_len(check_list)):
 				check_type = set_pop(check_list)
 				if (dict_in(cardinalities, check_type)):
@@ -163,12 +162,15 @@ String function conformance_scd(model : Element):
 								String error
 								error = (("Upper cardinality violation for outgoing edge of type " + check_type) + " at ") + model_info(model, model_name)
 								return error!
+			log("List iter OK")
 
 			// Identical, but for outgoing, and thus for A in the figure
 			if (bool_not(dict_in(spi_cache, type_name))):
 				dict_add(spi_cache, type_name, selectPossibleIncoming(metamodel, type_name, dict_keys(cardinalities)))
 
+			log("Set copy 2")
 			check_list = set_copy(spi_cache[type_name])
+			log("Done 2")
 			while (0 < list_len(check_list)):
 				check_type = set_pop(check_list)
 				if (dict_in(cardinalities, check_type)):
@@ -187,8 +189,9 @@ String function conformance_scd(model : Element):
 								String error
 								error = (("Upper cardinality violation for incoming edge of type " + check_type) + " at ") + model_info(model, model_name)
 								return error!
+			log("List iter OK 2")
 
-			constraint_function = read_attribute(metamodel, reverseKeyLookup(metamodel["model"], dict_read_node(typing, element)), "constraint")
+			constraint_function = read_attribute(metamodel, typing[model_name], "constraint")
 			if (element_neq(constraint_function, read_root())):
 				String result
 				result = constraint_function(model, model_name)
@@ -245,11 +248,11 @@ Element function generate_bottom_type_mapping(model : Element):
 	Element elem
 	elem_keys = dict_keys(model["model"])
 	while (0 < read_nr_out(elem_keys)):
-		elem = model["model"][set_pop(elem_keys)]
-		if (is_edge(elem)):
-			dict_add(tm, elem, mm["Edge"])
+		elem = set_pop(elem_keys)
+		if (is_edge(model["model"][elem])):
+			dict_add(tm, elem, "Edge")
 		else:
-			dict_add(tm, elem, mm["Node"])
+			dict_add(tm, elem, "Node")
 
 	return model!
 
@@ -259,7 +262,7 @@ String function model_info(model : Element, name : String):
 	String result
 	result = ""
 	result = (result + "\nModel name: ") + name
-	result = (result + "\nType: ") + cast_v2s(reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][name])))
+	result = (result + "\nType: ") + cast_v2s(model["type_mapping"][name])
 	result = (result + "\nValue: ") + cast_v2s(model["model"][name])
 	result = (result + "\nSource: ") + cast_v2s(reverseKeyLookup(model["model"], read_edge_src(model["model"][name])))
 	result = (result + "\nDestination: ") + cast_v2s(reverseKeyLookup(model["model"], read_edge_dst(model["model"][name])))

+ 4 - 1
bootstrap/library.alc

@@ -20,7 +20,10 @@ Element function export_node(model_name : String, model_reference : Element):
 		counter_i = counter_i + 1
 	
 	// current now contains the place where we should add the element
-	dict_add(current, splitted[length], model_reference)
+	if (bool_not(dict_in(current, splitted[length]))):
+		dict_add(current, splitted[length], model_reference)
+	else:
+		log("Could not export to that location: already in use!")
 
 	return model_reference!
 

+ 1 - 32
bootstrap/metamodels.alc

@@ -146,7 +146,7 @@ Element function constraint_call(model : Element, name : String):
 		return "Expected physical action value"!
 
 Element function initialize_SCD(location : String):
-	if (import_node(location) != read_root()):
+	if (element_neq(import_node(location), read_root())):
 		return import_node(location)!
 
 	Element scd
@@ -257,33 +257,6 @@ Element function initialize_PN(location_SCD : String, location_PN : String):
 
 	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()
@@ -306,19 +279,15 @@ 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)
 

+ 9 - 9
bootstrap/model_management.alc

@@ -31,7 +31,7 @@ Element function model_fuse(models : Element):
 		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]))
+			type = read_type(model, key)
 
 			if (is_edge(model["model"][key])):
 				String src
@@ -71,7 +71,7 @@ Element function model_copy(src_model : Element):
 
 			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]))
+			type = read_type(src_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
@@ -81,12 +81,12 @@ Element function model_copy(src_model : Element):
 
 		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]))
+			type = read_type(src_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]))
+			type = read_type(src_model, name)
 			instantiate_node(dst_model, type, name)
 
 	return dst_model!
@@ -104,17 +104,17 @@ Element function model_retype_on_name(model : Element, new_MM : Element, operati
 		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]))
+			type = read_type(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])
+				dict_delete(model["type_mapping"], key)
+				dict_add(model["type_mapping"], key, 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))])
+					dict_delete(model["type_mapping"], key)
+					dict_add(model["type_mapping"], key, string_substr(type, length, string_len(type)))
 				else:
 					model_delete_element(model, key)
 

+ 39 - 27
bootstrap/modelling.alc

@@ -84,10 +84,10 @@ Void function retype(model : Element, element : String, type : String):
 	// Retype a model, deleting any previous type the element had
 	// The type string is evaluated in the metamodel previously specified
 
-	if (dict_in_node(model["type_mapping"], model["model"][element])):
-		dict_delete_node(model["type_mapping"], model["model"][element])
+	if (dict_in(model["type_mapping"], element)):
+		dict_delete(model["type_mapping"], element)
 
-	dict_add(model["type_mapping"], model["model"][element], model["metamodel"]["model"][type])
+	dict_add(model["type_mapping"], element, type)
 
 	return!
 
@@ -152,13 +152,13 @@ Element function get_superclasses(model : Element, name : String):
 	Integer j
 	Integer num_edges
 	Element edge
-	Element elem
+	String elem
 	Element nodes
 	Element inheritance
 
 	nodes = create_node()
-	set_add(nodes, model["model"][name])
-	inheritance = model["metamodel"]["model"]["Inheritance"]
+	set_add(nodes, name)
+	inheritance = "Inheritance"
 
 	// Initialize empty set
 	result = create_node()
@@ -166,15 +166,15 @@ Element function get_superclasses(model : Element, name : String):
 
 	while (list_len(nodes) > 0):
 		elem = set_pop(nodes)
-		if (bool_not(set_in(result, reverseKeyLookup(model["model"], elem)))):
-			create_edge(result, reverseKeyLookup(model["model"], elem))
+		if (bool_not(set_in(result, elem))):
+			create_edge(result, elem)
 			// Read out all outgoing edges
-			num_edges = read_nr_out(elem)
+			num_edges = read_nr_out(model["model"][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))
+				edge = read_out(model["model"][elem], j)
+				if (value_eq(model["type_mapping"][reverseKeyLookup(model["model"], edge)], inheritance)):
+					set_add(nodes, reverseKeyLookup(model["model"], read_edge_dst(edge)))
 				j = j + 1
 
 	return result!
@@ -297,7 +297,7 @@ String function instantiate_link(model : Element, type : String, name : String,
 Void function model_delete_element(model : Element, name : String):
 	// Remove the link
 	// 1) from the type mapping
-	dict_delete_node(model["type_mapping"], model["model"][name])
+	dict_delete(model["type_mapping"], name)
 
 	// 2) from the model
 	delete_element(model["model"][name])
@@ -317,7 +317,7 @@ Element function read_attribute(model : Element, element : String, attribute : S
 	Integer i
 	Integer count
 	Element edge
-	Element edge_type
+	String edge_type
 	Element elem
 	Element typing
 
@@ -328,9 +328,9 @@ Element function read_attribute(model : Element, element : String, attribute : S
 	i = 0
 	while (i < count):
 		edge = read_out(elem, i)
-		if (dict_in_node(typing, edge)):
-			edge_type = dict_read_node(typing, edge)
-			if (element_eq(edge_type, dict_read_edge(read_edge_src(edge_type), attribute))):
+		if (dict_in(typing, reverseKeyLookup(model["model"], edge))):
+			edge_type = typing[reverseKeyLookup(model["model"], edge)]
+			if (edge_type == reverseKeyLookup(model["model"], dict_read_edge(read_edge_src(model["model"][edge_type]), attribute))):
 				return read_edge_dst(edge)!
 		i = i + 1
 
@@ -347,8 +347,8 @@ Void function unset_attribute(model : Element, element : String, attribute : Str
 
 	while (list_len(attr_links) > 0):
 		attr_link = set_pop(attr_links)
-		dict_delete_node(model["type_mapping"], read_edge_dst(model["model"][attr_link]))
-		dict_delete_node(model["type_mapping"], model["model"][attr_link])
+		dict_delete(model["type_mapping"], reverseKeyLookup(model["model"], read_edge_dst(model["model"][attr_link])))
+		dict_delete(model["type_mapping"], attr_link)
 		dict_delete_node(model["model"], reverseKeyLookup(model["model"], read_edge_dst(model["model"][attr_link])))
 		delete_element(model["model"][attr_link])
 
@@ -359,22 +359,29 @@ Void function add_AL_links(model : Element, list : Element, element : Element, t
 		return!
 
 	Element link
+	String link_name
+
 	link = dict_read_edge(element, linkname)
+	link_name = "__" + cast_id2s(link)
 
 	// The link
-	dict_add(model["model"], "__" + cast_id2s(link), link)
-	dict_add(model["type_mapping"], link, model["metamodel"]["model"][(type + "_") + linkname])
+	dict_add(model["model"], link_name, link)
+	dict_add(model["type_mapping"], link_name, (type + "_") + linkname)
 
 	// The name link
 	link = read_out(link, 0)
-	dict_add(model["model"], "__" + cast_id2s(link), link)
-	dict_add(model["type_mapping"], link, model["metamodel"]["model"]["to_str"])
+	link_name = "__" + cast_id2s(link)
+
+	dict_add(model["model"], link_name, link)
+	dict_add(model["type_mapping"], link_name, "to_str")
 
 	// The name node
 	link = read_edge_dst(link)
+	link_name = "__" + cast_id2s(link)
+
 	if (bool_not(set_in_node(model["model"], link))):
-		dict_add(model["model"], "__" + cast_id2s(link), link)
-		dict_add(model["type_mapping"], link, model["metamodel"]["model"]["String"])
+		dict_add(model["model"], link_name, link)
+		dict_add(model["type_mapping"], link_name, "String")
 
 	// Now add the destination to the worker list
 	Element node
@@ -391,6 +398,7 @@ String function add_AL(model : Element, element : Element):
 	Element work_node
 	Element elem
 	String type
+	String elem_name
 
 	todo = create_node()
 	node = create_node()
@@ -412,8 +420,9 @@ String function add_AL(model : Element, element : Element):
 					type = "Any"
 
 			// Add the node itself
-			dict_add(model["model"], "__" + cast_id2s(elem), elem)
-			dict_add(model["type_mapping"], elem, model["metamodel"]["model"][type])
+			elem_name = "__" + cast_id2s(elem)
+			dict_add(model["model"], elem_name, elem)
+			dict_add(model["type_mapping"], elem_name, type)
 
 			// Now add its edges
 			if (type == "if"):
@@ -477,10 +486,13 @@ Void function add_constraint(model : Element, element : String, constraint : Act
 Void function construct_model():
 	String command
 
+	log("Initialize SCD")
 	initialize_SCD("models/SimpleClassDiagrams")
+	log("Initialized!")
 
 	while (True):
 		command = input()
+		log(command)
 		if (command == "instantiate_bottom"):
 			Element m
 			m = instantiate_bottom()

+ 20 - 19
bootstrap/object_operations.alc

@@ -4,7 +4,6 @@ include "constructors.alh"
 include "modelling.alh"
 
 Element function allInstances(model : Element, type_name : String):
-	Element type_mapping
 	Element result
 	Element type
 
@@ -106,7 +105,7 @@ Element function getAttributeList(model : Element, element : String):
 	String attr_type
 
 	result = create_node()
-	types = get_superclasses(model["metamodel"], reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][element])))
+	types = get_superclasses(model["metamodel"], read_type(model, element))
 
 	while (read_nr_out(types) > 0):
 		type = set_pop(types)
@@ -147,17 +146,22 @@ Element function getInstantiatableAttributes(model : Element, element : String):
 	return result!
 
 String function reverseKeyLookup(dict : Element, element : Element):
-	Element elements
-	String name
-
-	elements = dict_keys(dict)
-	while (0 < list_len(elements)):
-		name = set_pop(elements)
-		if (element_eq(dict[name], element)):
-			return name!
-
+	Integer nr_in
+	Integer nr_out
+	Integer counter
+	Element link
+
+	nr_in = read_nr_in(element)
+	counter = 0
+	while (counter < nr_in):
+		if (element_eq(read_edge_src(read_in(element, counter)), dict)):
+			// Got a match
+			return (read_edge_dst(read_out(read_in(element, counter), 0)))!
+
+		counter = counter + 1
+	
 	return string_join(string_join("(unknown: ", cast_e2s(element)), " )")!
-
+	
 String function print_dict(dict : Element):
 	Element keys
 	Element key
@@ -215,7 +219,7 @@ Element function allowedAssociationsBetween(model : Element, src : String, dst :
 	String dst_name
 
 	result = create_node()
-	type = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][src]))
+	type = read_type(model, src)
 	all_types = get_superclasses(model["metamodel"], type)
 
 	while (read_nr_out(all_types) > 0):
@@ -241,16 +245,13 @@ Element function allowedAssociationsBetween(model : Element, src : String, dst :
 String function read_type(model : Element, name : String):
 	String result
 
-	Element mm
 	Element tm
 
-	mm = model["metamodel"]["model"]
 	if (dict_in(model["model"], name)):
-		if (dict_in_node(model["type_mapping"], model["model"][name])):
-			tm = dict_read_node(model["type_mapping"], model["model"][name])
+		if (dict_in(model["type_mapping"], name)):
+			result = model["type_mapping"][name]
 			
-			result = reverseKeyLookup(mm, tm)
-			if (element_eq(mm[result], tm)):
+			if (dict_in(model["metamodel"]["model"], result)):
 				return result!
 			else:
 				return ""!

+ 2 - 2
bootstrap/ramify.alc

@@ -135,7 +135,7 @@ Element function ramify(model : Element):
 		key = set_pop(keys)
 		entry = old_m[key]
 
-		type_name = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], entry))
+		type_name = read_type(model, entry)
 		if (type_name == "Class"):
 			log("Added Pre_" + key)
 			instantiate_node(new_model, type_name, "Pre_" + key)
@@ -166,7 +166,7 @@ Element function ramify(model : Element):
 
 	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))
+		type_name = read_type(model, 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

+ 5 - 5
bootstrap/transform.alc

@@ -70,7 +70,7 @@ Element function get_possible_bindings(host_model : Element, schedule_model : El
 
 	options = create_node()
 
-	typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][current_element]))
+	typename = read_type(schedule_model, current_element)
 	original_typename = string_substr(typename, 4, string_len(typename))
 
 	if (is_edge(schedule_model["model"][current_element])):
@@ -292,7 +292,7 @@ Void function rewrite(host_model : Element, schedule_model : Element, RHS : Stri
 			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]]))
+			typename = read_type(schedule_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)
@@ -304,7 +304,7 @@ Void function rewrite(host_model : Element, schedule_model : Element, RHS : Stri
 			// 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]]))
+				typename = read_type(schedule_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)
@@ -314,7 +314,7 @@ Void function rewrite(host_model : Element, schedule_model : Element, RHS : Stri
 		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]]))
+			typename = read_type(schedule_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)
@@ -373,7 +373,7 @@ Boolean function transform_composite(host_model : Element, schedule_model : Elem
 	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]))
+		typename = read_type(schedule_model, current)
 		if (typename == "Atomic"):
 			result = transform_atomic(host_model, schedule_model, current)
 		elif (typename == "Query"):

+ 13 - 21
core/mini_modify.alc

@@ -209,7 +209,7 @@ Element function modify(model : Element, write : Boolean):
 				v_m = set_pop(keys_m)
 				// Filter out anonymous objects
 				if (bool_not(string_startswith(v_m, "__"))):
-					typename = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][v_m]))
+					typename = read_type(model, v_m)
 					output((("  " + v_m) + " : ") + typename)
 
 		elif (cmd == "list_full"):
@@ -220,26 +220,22 @@ Element function modify(model : Element, write : Boolean):
 			while (read_nr_out(keys_m) > 0):
 				v_m = set_pop(keys_m)
 				// Filter out anonymous objects
-				typename = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][v_m]))
+				typename = read_type(model, v_m)
 				output((("  " + v_m) + " : ") + typename)
 
 		elif (cmd == "read"):
 			output("Element to read?")
 			cmd = input()
 			if (dict_in(model["model"], cmd)):
-				Element read_elem
-				read_elem = model["model"][cmd]
-				metamodel_element_pn = dict_read_node(model["type_mapping"], read_elem)
-
-				output("Name: " + cmd)
-				output("Type: " + reverseKeyLookup(model["metamodel"]["model"], metamodel_element_pn))
-				if (is_edge(read_elem)):
-					output("Source: " + reverseKeyLookup(model["model"], read_edge_src(read_elem)))
-					output("Destination: " + reverseKeyLookup(model["model"], read_edge_dst(read_elem)))
-				if (cast_v2s(read_elem) != "None"):
-					output("Value: " + cast_v2s(read_elem))
+				output("ID: " + cmd)
+				output("Type: " + read_type(model, cmd))
+				if (is_edge(model["model"][cmd])):
+					output("Source: " + reverseKeyLookup(model["model"], read_edge_src(model["model"][cmd])))
+					output("Destination: " + reverseKeyLookup(model["model"], read_edge_dst(model["model"][cmd])))
+				if (has_physical_value(model["model"][cmd])):
+					output("Value: " + cast_v2s(model["model"][cmd]))
 				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)
@@ -249,7 +245,7 @@ Element function modify(model : Element, write : Boolean):
 				attr_keys_pn = dict_keys(attr_list_pn)
 				while (0 < read_nr_out(attr_keys_pn)):
 					attr_key_pn = set_pop(attr_keys_pn)
-					output((((("  " + cast_v2s(attr_key_pn)) + " : ") + cast_v2s(attr_list_pn[attr_key_pn])) + " = ") + cast_v2s(read_attribute(model, reverseKeyLookup(model["model"], read_elem), attr_key_pn)))
+					output((((("  " + cast_v2s(attr_key_pn)) + " : ") + cast_v2s(attr_list_pn[attr_key_pn])) + " = ") + cast_v2s(read_attribute(model, cmd, attr_key_pn)))
 			else:
 				output("Unknown element; aborting")
 
@@ -264,7 +260,7 @@ Element function modify(model : Element, write : Boolean):
 			while (read_nr_out(keys_t) > 0):
 				v_t = set_pop(keys_t)
 				if (bool_not(string_startswith(v_t, "__"))):
-					output(string_join(("  " + v_t) + " : ", reverseKeyLookup(model["metamodel"]["metamodel"]["model"], dict_read_node(model["metamodel"]["type_mapping"], model["metamodel"]["model"][v_t]))))
+					output(string_join(("  " + v_t) + " : ", read_type(model, v_t)))
 
 		elif (cmd == "retype"):
 			if (write):
@@ -275,11 +271,7 @@ Element function modify(model : Element, write : Boolean):
 					output("New type")
 					typename = input()
 					if (dict_in(model["metamodel"]["model"], typename)):
-						// OK, do the retyping
-						// First try removing the previous type if it exists
-						dict_delete_node(model["type_mapping"], model["model"][elementname])
-						// Now add the new type
-						dict_add(model["type_mapping"], model["model"][elementname], model["metamodel"]["model"][typename])
+						retype(model, elementname, typename)
 						output("Retyped!")
 					else:
 						output("Unknown type; aborting")

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

@@ -1,6 +1,5 @@
 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)

+ 388 - 0
kernel/modelverse_kernel/compiled.py

@@ -0,0 +1,388 @@
+from modelverse_kernel.primitives import PrimitiveFinished
+import modelverse_jit.runtime as jit_runtime 
+
+def reverseKeyLookup(a, b, **remainder):
+    edges, = yield [("RO", [a])]
+    expanded_edges = yield [("RE", [i]) for i in edges]
+    for i, edge in enumerate(expanded_edges):
+        if b == edge[1]:
+            # Found our edge: edges[i]
+            outgoing, = yield [("RO", [edges[i]])]
+            result, = yield [("RE", [outgoing[0]])]
+            raise PrimitiveFinished(result[1])
+
+    result, = yield [("CNV", ["(unknown: %s)" % b])]
+    raise PrimitiveFinished(result)
+
+"""
+def read_attribute(a, b, c, **remainder):
+    model_dict, b_val, c_val, type_mapping = \
+                    yield [("RD", [a, "model"]),
+                           ("RV", [b]),
+                           ("RV", [c]),
+                           ("RD", [a, "type_mapping"]),
+                           ]
+    model_instance, = \
+                    yield [("RD", [model_dict, b_val])]
+    edges, =        yield [("RO", [model_instance])]
+    edge_types =    yield [("RDN", [type_mapping, i]) for i in edges]
+    type_edge_val = yield [("RE", [i]) for i in edge_types]
+
+    src_nodes = set([i[0] for i in type_edge_val])
+
+    found_edges =   yield [("RDE", [i, c_val]) for i in src_nodes]
+
+    for e1 in found_edges:
+        if e1 is not None:
+            # Found an edge!
+            for i, e2 in enumerate(edge_types):
+                if e1 == e2:
+                    # The instance of this edge is the one we want!
+                    edge = edges[i]
+                    edge_val, = yield [("RE", [edge])]
+                    result = edge_val[1]
+                    raise PrimitiveFinished(result)
+    else:
+        result, = yield [("RR", [])]
+        raise PrimitiveFinished(result)
+
+    raise Exception("Error in reading edge!")
+"""
+
+def set_copy(a, **remainder):
+    b, =         yield [("CN", [])]
+    links, =     yield [("RO", [a])]
+    exp_links = yield [("RE", [i]) for i in links]
+    _ =         yield [("CE", [b, i[1]]) for i in exp_links]
+    raise PrimitiveFinished(b)
+
+"""
+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])]
+    elems =     yield [("RDN", [model_dict, i]) for i in elem_keys]
+    mms =       yield [("RDN", [typing, i]) for i in elems]
+
+    # Have the type for each name
+    types_to_name_nodes = {}
+    for key, mm in zip(elem_keys, mms):
+        types_to_name_nodes.setdefault(mm, set()).add(key)
+    # 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", [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"])]
+
+    while work_list:
+        mm_element = work_list.pop()
+        if mm_element in desired_types:
+            # Already been here, so stop
+            continue
+
+        # New element, so continue
+        desired_types.add(mm_element)
+
+        # Follow all inheritance links that COME IN this node, as all these are subtypes and should also match
+        incoming, =  yield [("RI", [mm_element])]
+        for i in incoming:
+            t, =     yield [("RDN", [mm_typing, i])]
+            if t == inheritance_type:
+                e, = yield [("RE", [i])]
+                # Add the source of the inheritance link to the work list
+                work_list.append(e[0])
+
+    # Now desired_types holds all the direct types that we are interested in!
+    # Construct the result out of all models that are direct instances of our specified type
+    final = set()
+    for t in desired_types:
+        final |= types_to_name_nodes.get(t, set())
+
+    # Result is a Python set with nodes, so just make this a Mv set
+    result, =    yield [("CN", [])]
+    v =         yield [("RV", [i]) for i in final]
+    _ =    yield [("CE", [result, i]) for i in final]
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def add_AL(a, b, **remainder):
+    worklist = [(b, "funcdef")]
+    added = set()
+    type_cache = {}
+
+    model_dict, = yield [("RD", [a, "model"])]
+    metamodel, = yield [("RD", [a, "metamodel"])]
+    metamodel_dict, = yield [("RD", [metamodel, "model"])]
+    type_map, = yield [("RD", [a, "type_mapping"])]
+    outgoing, = yield [("RO", [model_dict])]
+    edges = yield [("RE", [i]) for i in outgoing]
+    added |= set([i[1] for i in edges])
+
+    result, = yield [("CNV", ["__%s" % b])]
+
+    # All the action language elements and their expected output links
+    type_links = {
+            "if":       [("cond", ""), ("then", ""), ("else", ""), ("next", "")],
+            "while":    [("cond", ""), ("body", ""), ("next", "")],
+            "assign":   [("var", ""), ("value", ""), ("next", "")],
+            "break":    [("while", "while")],
+            "continue": [("while", "while")],
+            "return":   [("value", "")],
+            "resolve":  [("var", "")],
+            "access":   [("var", "")],
+            "constant": [("node", "")],
+            "output":   [("node", ""), ("next", "")],
+            "global":   [("var", "String"), ("next", "")],
+            "param":    [("name", "String"), ("value", ""), ("next_param", "param")],
+            "funcdef":  [("body", ""), ("next", "")],
+            "call":     [("func", ""), ("params", "param"), ("last_param", "param"), ("next", "")],
+        }
+
+    # Already add some often used types to the type cache, so we don't have to check for their presence
+    to_str, string = yield [("RD", [metamodel_dict, "to_str"]),
+                            ("RD", [metamodel_dict, "String"])]
+
+    type_cache = {"to_str": to_str,
+                  "String": string}
+
+    while worklist:
+        # Fetch the element and see if we need to add it
+        worknode, expected_type = worklist.pop(0)
+        if worknode in added:
+            continue
+
+        # Determine type of element
+        if expected_type == "":
+            value, = yield [("RV", [worknode])]
+            if (isinstance(value, dict)) and ("value" in value):
+                v = value["value"]
+                if v in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]:
+                    expected_type = v
+                else:
+                    expected_type = "Any"
+            else:
+                expected_type = "Any"
+
+        # Fill the cache
+        if expected_type not in type_cache:
+            type_cache[expected_type], = yield [("RD", [metamodel_dict, expected_type])]
+
+        # Need to add it now
+        yield [("CD", [model_dict, "__%s" % worknode, worknode])]
+        added.add(worknode)
+        # NOTE can't just use CD here, as the key is a node and not a value
+        t1, = yield [("CE", [type_map, type_cache[expected_type]])]
+        t2, = yield [("CE", [t1, worknode])]
+        if t1 is None or t2 is None:
+            raise Exception("ERROR")
+
+        # Now add all its outgoing links, depending on the type we actually saw
+        links = type_links.get(expected_type, [])
+        for link in links:
+            link_name, destination_type = link
+
+            # Check if the link actually exists
+            destination, = yield [("RD", [worknode, link_name])]
+            if destination is not None:
+                # If so, we add it and continue
+                edge, = yield [("RDE", [worknode, link_name])]
+                edge_outlinks, = yield [("RO", [edge])]
+                edge_outlink = edge_outlinks[0]
+                edge_name, = yield [("RE", [edge_outlink])]
+                edge_name = edge_name[1]
+                # Now add: edge, edge_outlink, edge_name
+
+                # Add 'edge'
+                yield [("CD", [model_dict, "__%s" % edge, edge])]
+                added.add(edge)
+                link_type = "%s_%s" % (expected_type, link_name)
+                if link_type not in type_cache:
+                    type_cache[link_type], = yield [("RD", [metamodel_dict, link_type])]
+                t, = yield [("CE", [type_map, type_cache[link_type]])]
+                yield [("CE", [t, edge])]
+
+                # Add 'edge_outlink'
+                yield [("CD", [model_dict, "__%s" % edge_outlink, edge_outlink])]
+                added.add(edge_outlink)
+                t, = yield [("CE", [type_map, type_cache["to_str"]])]
+                yield [("CE", [t, edge_outlink])]
+
+                # Add 'edge_name' (if not present)
+                if edge_name not in added:
+                    yield [("CD", [model_dict, "__%s" % edge_name, edge_name])]
+                    t, = yield [("CE", [type_map, type_cache["String"]])]
+                    yield [("CE", [t, edge_name])]
+                    added.add(edge_name)
+
+                # Add the destination to the worklist
+                worklist.append((destination, destination_type))
+
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def get_superclasses(a, b, **remainder):
+    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])]
+    type_mapping, =  yield [("RD", [a, "type_mapping"])]
+    names, =         yield [("RDK", [model_dict])]
+    elems =         yield [("RDN", [model_dict, i]) for i in names]
+    elem_to_name =  dict(zip(elems, names))
+
+    result, =        yield [("CN", [])]
+    worklist = [subclass]
+
+    touched = set()
+
+    while worklist:
+        subclass = worklist.pop()
+        res = elem_to_name[subclass]
+
+        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)
+                    if dst is None:
+                        print("Read edge gives error for edge: " + str(elem))
+
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def selectPossibleIncoming(a, b, c, **remainder):
+    model_dict, =    yield [("RD", [a, "model"])]
+    limit_set_links, = \
+                    yield [("RO", [c])]
+    limit_set =     yield [("RE", [i]) for i in limit_set_links]
+    limit_set_names = [i[1] for i in limit_set]
+    name_values =   yield [("RV", [i]) for i in limit_set_names]
+    limit_set =     yield [("RD", [model_dict, i]) for i in name_values]
+
+    superclasses, = yield [("CALL_ARGS", [get_superclasses, (a, b)])]
+    vals, = yield [("RO", [superclasses])]
+    superclasses = yield [("RE", [i]) for i in vals]
+    superclasses = [i[1] for i in superclasses]
+
+    superclass_names = yield [("RV", [i]) for i in superclasses]
+    elems =         yield [("RD", [model_dict, i]) for i in superclass_names]
+
+    result, =        yield [("CN", [])]
+    for i, edge in enumerate(limit_set):
+        srcdst, =  yield [("RE", [edge])]
+        src, dst = srcdst
+        if dst in elems:
+            yield [("CE", [result, limit_set_names[i]])]
+
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def selectPossibleOutgoing(a, b, c, **remainder):
+    model_dict, =    yield [("RD", [a, "model"])]
+    limit_set_links, = \
+                    yield [("RO", [c])]
+    limit_set =     yield [("RE", [i]) for i in limit_set_links]
+    limit_set_names = \
+                    [i[1] for i in limit_set]
+    name_values =   yield [("RV", [i]) for i in limit_set_names]
+    limit_set =     yield [("RD", [model_dict, i]) for i in name_values]
+
+    superclasses, = yield [("CALL_ARGS", [get_superclasses, (a, b)])]
+    vals, = yield [("RO", [superclasses])]
+    superclasses = yield [("RE", [i]) for i in vals]
+    superclasses = [i[1] for i in superclasses]
+
+    superclass_names = yield [("RV", [i]) for i in superclasses]
+    elems =         yield [("RD", [model_dict, i]) for i in superclass_names]
+
+    result, =        yield [("CN", [])]
+    for i, edge in enumerate(limit_set):
+        srcdst, =  yield [("RE", [edge])]
+        src, dst = srcdst
+        if src in elems:
+            yield [("CE", [result, limit_set_names[i]])]
+
+    raise PrimitiveFinished(result)
+"""
+
+def check_symbols(a, b, c, **remainder):
+    symbols = {}
+    function_name, = yield [("RV", [b])]
+    symbols[function_name] = False
+    object_links, = yield [("RO", [c])]
+    set_elements = yield [("RE", [i]) for i in object_links]
+    set_elements = [i[1] for i in set_elements]
+    set_values = yield [("RV", [i]) for i in set_elements]
+    set_elements = yield [("RD", [a, i]) for i in set_values]
+    symbols_set = yield [("RD", [i, "symbols"]) for i in set_elements]
+    all_keys = yield [("RDK", [i]) for i in symbols_set]
+    for i, s in zip(all_keys, symbols_set):
+        # For each object we have found
+        keys = yield [("RV", [j]) for j in i]
+        values = yield [("RD", [s, j]) for j in keys]
+        values = yield [("RV", [j]) for j in values]
+        for key, value in zip(keys, values):
+            k = key
+            v = value
+            if v and symbols.get(k, False):
+                result, = yield [("CNV", ["ERROR: multiple definition of symbol " + str(key)])]
+                raise PrimitiveFinished(result)
+            elif v and not symbols.get(k, False):
+                symbols[k] = True
+            elif not v and k not in symbols:
+                symbols[k] = False
+
+    for i, j in symbols.items():
+        if i == "input" or i == "output":
+            continue
+        if not j:
+            result, = yield [("CNV", ["ERROR: undefined symbol " + str(i)])]
+            raise PrimitiveFinished(result)
+
+    result, = yield [("CNV", ["OK"])]
+    raise PrimitiveFinished(result)
+
+def construct_const(**remainder):
+    v, = yield [("CNV", [{"value": "constant"}])]
+
+    # Get input: keep trying until we get something
+    inp, = yield [("CALL_KWARGS", [jit_runtime.get_input, remainder])]
+
+    yield [("CD", [v, "node", inp])]
+
+    raise PrimitiveFinished(v)
+
+def instantiated_name(a, b, **remainder):
+    name_value, = yield [("RV", [b])]
+    if name_value == "":
+        b, = yield [("CNV", ["__" + str(a)])]
+    raise PrimitiveFinished(b)

+ 421 - 0
kernel/modelverse_kernel/compiled_legacy.py

@@ -0,0 +1,421 @@
+from modelverse_kernel.primitives import PrimitiveFinished
+
+def reverseKeyLookup(a, b, **remainder):
+    edges, = yield [("RO", [a])]
+    expanded_edges = yield [("RE", [i]) for i in edges]
+    for i, edge in enumerate(expanded_edges):
+        if b == edge[1]:
+            # Found our edge: edges[i]
+            outgoing, = yield [("RO", [edges[i]])]
+            result, = yield [("RE", [outgoing[0]])]
+            raise PrimitiveFinished(result[1])
+
+    result, = yield [("CNV", ["(unknown: %s)" % b])]
+    raise PrimitiveFinished(result)
+
+"""
+def read_attribute(a, b, c, **remainder):
+    model_dict, b_val, c_val, type_mapping = \
+                    yield [("RD", [a, "model"]),
+                           ("RV", [b]),
+                           ("RV", [c]),
+                           ("RD", [a, "type_mapping"]),
+                           ]
+    model_instance, = \
+                    yield [("RD", [model_dict, b_val])]
+    edges, =        yield [("RO", [model_instance])]
+    edge_types =    yield [("RDN", [type_mapping, i]) for i in edges]
+    type_edge_val = yield [("RE", [i]) for i in edge_types]
+
+    src_nodes = set([i[0] for i in type_edge_val])
+
+    found_edges =   yield [("RDE", [i, c_val]) for i in src_nodes]
+
+    for e1 in found_edges:
+        if e1 is not None:
+            # Found an edge!
+            for i, e2 in enumerate(edge_types):
+                if e1 == e2:
+                    # The instance of this edge is the one we want!
+                    edge = edges[i]
+                    edge_val, = yield [("RE", [edge])]
+                    result = edge_val[1]
+                    raise PrimitiveFinished(result)
+    else:
+        result, = yield [("RR", [])]
+        raise PrimitiveFinished(result)
+
+    raise Exception("Error in reading edge!")
+"""
+
+def set_copy(a, **remainder):
+    b, =         yield [("CN", [])]
+    links, =     yield [("RO", [a])]
+    exp_links = yield [("RE", [i]) for i in links]
+    _ =         yield [("CE", [b, i[1]]) for i in exp_links]
+    raise PrimitiveFinished(b)
+
+"""
+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])]
+    elems =     yield [("RDN", [model_dict, i]) for i in elem_keys]
+    mms =       yield [("RDN", [typing, i]) for i in elems]
+
+    # Have the type for each name
+    types_to_name_nodes = {}
+    for key, mm in zip(elem_keys, mms):
+        types_to_name_nodes.setdefault(mm, set()).add(key)
+    # 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", [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"])]
+
+    while work_list:
+        mm_element = work_list.pop()
+        if mm_element in desired_types:
+            # Already been here, so stop
+            continue
+
+        # New element, so continue
+        desired_types.add(mm_element)
+
+        # Follow all inheritance links that COME IN this node, as all these are subtypes and should also match
+        incoming, =  yield [("RI", [mm_element])]
+        for i in incoming:
+            t, =     yield [("RDN", [mm_typing, i])]
+            if t == inheritance_type:
+                e, = yield [("RE", [i])]
+                # Add the source of the inheritance link to the work list
+                work_list.append(e[0])
+
+    # Now desired_types holds all the direct types that we are interested in!
+    # Construct the result out of all models that are direct instances of our specified type
+    final = set()
+    for t in desired_types:
+        final |= types_to_name_nodes.get(t, set())
+
+    # Result is a Python set with nodes, so just make this a Mv set
+    result, =    yield [("CN", [])]
+    v =         yield [("RV", [i]) for i in final]
+    _ =    yield [("CE", [result, i]) for i in final]
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def add_AL(a, b, **remainder):
+    worklist = [(b, "funcdef")]
+    added = set()
+    type_cache = {}
+
+    model_dict, = yield [("RD", [a, "model"])]
+    metamodel, = yield [("RD", [a, "metamodel"])]
+    metamodel_dict, = yield [("RD", [metamodel, "model"])]
+    type_map, = yield [("RD", [a, "type_mapping"])]
+    outgoing, = yield [("RO", [model_dict])]
+    edges = yield [("RE", [i]) for i in outgoing]
+    added |= set([i[1] for i in edges])
+
+    result, = yield [("CNV", ["__%s" % b])]
+
+    # All the action language elements and their expected output links
+    type_links = {
+            "if":       [("cond", ""), ("then", ""), ("else", ""), ("next", "")],
+            "while":    [("cond", ""), ("body", ""), ("next", "")],
+            "assign":   [("var", ""), ("value", ""), ("next", "")],
+            "break":    [("while", "while")],
+            "continue": [("while", "while")],
+            "return":   [("value", "")],
+            "resolve":  [("var", "")],
+            "access":   [("var", "")],
+            "constant": [("node", "")],
+            "output":   [("node", ""), ("next", "")],
+            "global":   [("var", "String"), ("next", "")],
+            "param":    [("name", "String"), ("value", ""), ("next_param", "param")],
+            "funcdef":  [("body", ""), ("next", "")],
+            "call":     [("func", ""), ("params", "param"), ("last_param", "param"), ("next", "")],
+        }
+
+    # Already add some often used types to the type cache, so we don't have to check for their presence
+    to_str, string = yield [("RD", [metamodel_dict, "to_str"]),
+                            ("RD", [metamodel_dict, "String"])]
+
+    type_cache = {"to_str": to_str,
+                  "String": string}
+
+    while worklist:
+        # Fetch the element and see if we need to add it
+        worknode, expected_type = worklist.pop(0)
+        if worknode in added:
+            continue
+
+        # Determine type of element
+        if expected_type == "":
+            value, = yield [("RV", [worknode])]
+            if (isinstance(value, dict)) and ("value" in value):
+                v = value["value"]
+                if v in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]:
+                    expected_type = v
+                else:
+                    expected_type = "Any"
+            else:
+                expected_type = "Any"
+
+        # Fill the cache
+        if expected_type not in type_cache:
+            type_cache[expected_type], = yield [("RD", [metamodel_dict, expected_type])]
+
+        # Need to add it now
+        yield [("CD", [model_dict, "__%s" % worknode, worknode])]
+        added.add(worknode)
+        # NOTE can't just use CD here, as the key is a node and not a value
+        t1, = yield [("CE", [type_map, type_cache[expected_type]])]
+        t2, = yield [("CE", [t1, worknode])]
+        if t1 is None or t2 is None:
+            raise Exception("ERROR")
+
+        # Now add all its outgoing links, depending on the type we actually saw
+        links = type_links.get(expected_type, [])
+        for link in links:
+            link_name, destination_type = link
+
+            # Check if the link actually exists
+            destination, = yield [("RD", [worknode, link_name])]
+            if destination is not None:
+                # If so, we add it and continue
+                edge, = yield [("RDE", [worknode, link_name])]
+                edge_outlinks, = yield [("RO", [edge])]
+                edge_outlink = edge_outlinks[0]
+                edge_name, = yield [("RE", [edge_outlink])]
+                edge_name = edge_name[1]
+                # Now add: edge, edge_outlink, edge_name
+
+                # Add 'edge'
+                yield [("CD", [model_dict, "__%s" % edge, edge])]
+                added.add(edge)
+                link_type = "%s_%s" % (expected_type, link_name)
+                if link_type not in type_cache:
+                    type_cache[link_type], = yield [("RD", [metamodel_dict, link_type])]
+                t, = yield [("CE", [type_map, type_cache[link_type]])]
+                yield [("CE", [t, edge])]
+
+                # Add 'edge_outlink'
+                yield [("CD", [model_dict, "__%s" % edge_outlink, edge_outlink])]
+                added.add(edge_outlink)
+                t, = yield [("CE", [type_map, type_cache["to_str"]])]
+                yield [("CE", [t, edge_outlink])]
+
+                # Add 'edge_name' (if not present)
+                if edge_name not in added:
+                    yield [("CD", [model_dict, "__%s" % edge_name, edge_name])]
+                    t, = yield [("CE", [type_map, type_cache["String"]])]
+                    yield [("CE", [t, edge_name])]
+                    added.add(edge_name)
+
+                # Add the destination to the worklist
+                worklist.append((destination, destination_type))
+
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def get_superclasses(a, b, **remainder):
+    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])]
+    type_mapping, =  yield [("RD", [a, "type_mapping"])]
+    names, =         yield [("RDK", [model_dict])]
+    elems =         yield [("RDN", [model_dict, i]) for i in names]
+    elem_to_name =  dict(zip(elems, names))
+
+    result, =        yield [("CN", [])]
+    worklist = [subclass]
+
+    touched = set()
+
+    while worklist:
+        subclass = worklist.pop()
+        res = elem_to_name[subclass]
+
+        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)
+"""
+
+"""
+def selectPossibleIncoming(a, b, c, **remainder):
+    model_dict, =    yield [("RD", [a, "model"])]
+    limit_set_links, = \
+                    yield [("RO", [c])]
+    limit_set =     yield [("RE", [i]) for i in limit_set_links]
+    limit_set_names = [i[1] for i in limit_set]
+    name_values =   yield [("RV", [i]) for i in limit_set_names]
+    limit_set =     yield [("RD", [model_dict, i]) for i in name_values]
+
+    try:
+        gen = get_superclasses(a, b)
+        inp = None
+        while 1:
+            inp =   yield gen.send(inp)
+    except PrimitiveFinished as e:
+        superclasses = e.result
+        vals, = yield [("RO", [superclasses])]
+        superclasses = yield [("RE", [i]) for i in vals]
+        superclasses = [i[1] for i in superclasses]
+
+    superclass_names = yield [("RV", [i]) for i in superclasses]
+    elems =         yield [("RD", [model_dict, i]) for i in superclass_names]
+
+    result, =        yield [("CN", [])]
+    for i, edge in enumerate(limit_set):
+        srcdst, =  yield [("RE", [edge])]
+        src, dst = srcdst
+        if dst in elems:
+            yield [("CE", [result, limit_set_names[i]])]
+
+    raise PrimitiveFinished(result)
+"""
+
+"""
+def selectPossibleOutgoing(a, b, c, **remainder):
+    model_dict, =    yield [("RD", [a, "model"])]
+    limit_set_links, = \
+                    yield [("RO", [c])]
+    limit_set =     yield [("RE", [i]) for i in limit_set_links]
+    limit_set_names = \
+                    [i[1] for i in limit_set]
+    name_values =   yield [("RV", [i]) for i in limit_set_names]
+    limit_set =     yield [("RD", [model_dict, i]) for i in name_values]
+
+    try:
+        gen = get_superclasses(a, b)
+        inp = None
+        while 1:
+            inp =  yield gen.send(inp)
+    except PrimitiveFinished as e:
+        superclasses = e.result
+        vals, = yield [("RO", [superclasses])]
+        superclasses = yield [("RE", [i]) for i in vals]
+        superclasses = [i[1] for i in superclasses]
+
+    superclass_names = yield [("RV", [i]) for i in superclasses]
+    elems =         yield [("RD", [model_dict, i]) for i in superclass_names]
+
+    result, =        yield [("CN", [])]
+    for i, edge in enumerate(limit_set):
+        srcdst, =  yield [("RE", [edge])]
+        src, dst = srcdst
+        if src in elems:
+            yield [("CE", [result, limit_set_names[i]])]
+
+    raise PrimitiveFinished(result)
+"""
+
+def check_symbols(a, b, c, **remainder):
+    symbols = {}
+    function_name, = yield [("RV", [b])]
+    symbols[function_name] = False
+    object_links, = yield [("RO", [c])]
+    set_elements = yield [("RE", [i]) for i in object_links]
+    set_elements = [i[1] for i in set_elements]
+    set_values = yield [("RV", [i]) for i in set_elements]
+    set_elements = yield [("RD", [a, i]) for i in set_values]
+    symbols_set = yield [("RD", [i, "symbols"]) for i in set_elements]
+    all_keys = yield [("RDK", [i]) for i in symbols_set]
+    for i, s in zip(all_keys, symbols_set):
+        # For each object we have found
+        keys = yield [("RV", [j]) for j in i]
+        values = yield [("RD", [s, j]) for j in keys]
+        values = yield [("RV", [j]) for j in values]
+        for key, value in zip(keys, values):
+            k = key
+            v = value
+            if v and symbols.get(k, False):
+                result = yield [("CNV", ["ERROR: multiple definition of symbol " + str(key)])]
+                raise PrimitiveFinished(result)
+            elif v and not symbols.get(k, False):
+                symbols[k] = True
+            elif not v and k not in symbols:
+                symbols[k] = False
+
+    for i, j in symbols.items():
+        if i == "input" or i == "output":
+            continue
+        if not j:
+            result, = yield [("CNV", ["ERROR: undefined symbol " + str(i)])]
+            raise PrimitiveFinished(result)
+
+    result, = yield [("CNV", ["OK"])]
+    raise PrimitiveFinished(result)
+
+def construct_const(**remainder):
+    v, = yield [("CNV", [{"value": "constant"}])]
+
+    # Get input: keep trying until we get something
+    try:
+        gen = __get_input(remainder)
+        inp = None
+        while 1:
+            inp = yield gen.send(inp)
+    except PrimitiveFinished as e:
+        inp = e.result
+
+    yield [("CD", [v, "node", inp])]
+
+    raise PrimitiveFinished(v)
+
+def instantiated_name(a, b, **remainder):
+    name_value, = yield [("RV", [b])]
+    if name_value == "":
+        b, = yield [("CNV", ["__" + str(a)])]
+    raise PrimitiveFinished(b)
+
+def __get_input(parameters):
+    mvk = parameters["mvk"]
+    user_root = parameters["user_root"]
+    while 1:
+        try:
+            gen = mvk.input_init(user_root)
+            inp = None
+            while 1:
+                inp = yield gen.send(inp)
+        except StopIteration:
+            # Finished
+            if mvk.success:
+                # Got some input, so we can access it
+                raise PrimitiveFinished(mvk.input_value)
+            else:
+                # No input, so yield None but don't stop
+                yield None

+ 1 - 0
state/modelverse_state/main.py

@@ -250,6 +250,7 @@ class ModelverseState(object):
                     # Now get the target of the original link
                     if found is not None:
                         print("Duplicate key on value: %s : %s (%s <-> %s)!" % (v, type(v), found, e1))
+                        raise Exception()
                         return (None, status.FAIL_RDICTE_AMBIGUOUS)
                     found = e1
                     self.cache.setdefault(node, {})[value] = e1