Browse Source

Merge branch 'yentl'

Yentl Van Tendeloo 9 years ago
parent
commit
35aed7817c
39 changed files with 98624 additions and 1148 deletions
  1. 0 1
      .gitignore
  2. 95835 0
      bootstrap/bootstrap.m
  3. 1 0
      bootstrap/bootstrap.py
  4. 88 23
      bootstrap/compilation_manager.alc
  5. 21 22
      bootstrap/conformance_scd.alc
  6. 20 7
      bootstrap/constructors.alc
  7. 9 7
      bootstrap/metamodels.alc
  8. 1859 0
      bootstrap/minimal.m
  9. 18 0
      bootstrap/object_operations.alc
  10. 11 0
      bootstrap/primitives.alc
  11. 26 0
      bootstrap/random.alc
  12. 0 2
      hybrid_server/classes/mvkcontroller.xml
  13. 0 151
      integration/code/b2dc.txt
  14. 0 326
      integration/code/import_metamodel_cs.txt
  15. 20 9
      integration/code/pn_interface.alc
  16. 1 1
      integration/test_binary2decimal.py
  17. 3 0
      integration/test_constructors_models.py
  18. 1 1
      integration/test_factorial.py
  19. 1 1
      integration/test_fibonacci.py
  20. 1 1
      integration/test_fibonacci_smart.py
  21. 2 2
      integration/test_if_elif.py
  22. 1 1
      integration/test_leap_year.py
  23. 202 97
      integration/test_pn_interface.py
  24. 1 1
      integration/test_power.py
  25. 1 1
      integration/test_remainder.py
  26. 1 1
      integration/test_revert.py
  27. 52 11
      integration/utils.py
  28. 9 81
      interface/HUTN/hutn_compiler/linker.py
  29. 1 0
      interface/HUTN/includes/compilation_manager.alh
  30. 1 0
      interface/HUTN/includes/conformance_scd.alh
  31. 3 0
      interface/HUTN/includes/object_operations.alh
  32. 3 0
      interface/HUTN/includes/primitives.alh
  33. 3 0
      interface/HUTN/includes/random.alh
  34. 115 112
      kernel/modelverse_kernel/compiled.py
  35. 105 114
      kernel/modelverse_kernel/main.py
  36. 131 140
      kernel/modelverse_kernel/primitives.py
  37. 0 2
      kernel/test/utils.py
  38. 75 30
      model/model.py
  39. 3 3
      scripts/prompt.py

+ 0 - 1
.gitignore

@@ -1,6 +1,5 @@
 *.pyc
 *.pickle
-*.m
 *.dot
 .cache
 *.swp

File diff suppressed because it is too large
+ 95835 - 0
bootstrap/bootstrap.m


+ 1 - 0
bootstrap/bootstrap.py

@@ -92,6 +92,7 @@ def bootstrap():
                     "element_eq": ["Boolean", "Element", "Element"],
                     "element_neq": ["Boolean", "Element", "Element"],
                     "read_root": ["Element"],
+                    "read_userroot": ["Element"],
                     "deserialize": ["Element", "String"],
                     "log": ["String", "String"],
                 }

+ 88 - 23
bootstrap/compilation_manager.alc

@@ -1,24 +1,8 @@
 include "primitives.alh"
 include "constructors.alh"
+include "conformance_scd.alh"
 
-Element function read_symbols(root : Element, object_name : String):
-	Element keys
-	Element node
-	String rv
-	String key
-
-	node = root[object_name]["symbols"]
-	keys = dict_keys(node)
-	rv = ""
-	while (0 < read_nr_out(keys)):
-		key = set_pop(keys)
-		if (node[key]):
-			rv = (rv + key) + ":1\n"
-		else:
-			rv = (rv + key) + ":0\n"
-	return rv
-
-Element function compilation_manager():
+Void function compilation_manager():
 	String operation
 	String object_name
 	Element root
@@ -49,13 +33,25 @@ Element function compilation_manager():
 		dict_add(node, "symbols", symbols)
 		while (input()):
 			dict_add(symbols, input(), input())
-	elif (operation == "read_symbols"):
-		output(read_symbols(root, input()))
+	elif (operation == "remove_obj"):
+		dict_delete(root, input())
 	elif (operation == "read_initializers"):
 		node = root[input()]["initializers"]
 		output(node)
-	elif (operation == "remove_obj"):
-		dict_delete(root, input())
+	elif (operation == "link_and_load"):
+		Element objs
+		String obj
+
+		objs = create_node()
+		obj = input()
+		while (obj != ""):
+			if (dict_in(root, obj)):
+				set_add(objs, obj)
+			else:
+				log("ERROR: couldn't find obj " + obj)
+			obj = input()
+
+		link_and_load(root, input(), objs)
 	elif (operation == "is_defined"):
 		object_name = input()
 		if (dict_in(root, object_name)):
@@ -64,4 +60,73 @@ Element function compilation_manager():
 			output(create_node())
 	else:
 		log("Failed to understand command")
-	return operation
+
+	return
+
+String function check_symbols(root : Element, main_function : String, objs : Element):
+	Element symbols
+	String obj
+	Element keys
+	String key
+	Element copy_objs
+
+	// We always need a main variable
+	symbols = create_node()
+	dict_add(symbols, main_function, False)
+
+	// Resolve all symbols
+	copy_objs = set_copy(objs)
+	while (0 < list_len(copy_objs)):
+		obj = set_pop(copy_objs)
+		keys = dict_keys(root[obj]["symbols"])
+		while (0 < list_len(keys)):
+			key = set_pop(keys)
+
+			if (root[obj]["symbols"][key]):
+				// Defines
+				if (bool_not(dict_in(symbols, key))):
+					// Not yet in dictionary
+					dict_add(symbols, key, True)
+				elif (symbols[key]):
+					// Already in dictionary, and it was already defined
+					return "ERROR: multiple definition of symbol " + key
+				else:
+					// Already in dictionary, but only used
+					dict_delete(symbols, key)
+					dict_add(symbols, key, True)
+			else:
+				// Uses
+				if (bool_not(dict_in(symbols, key))):
+					dict_add(symbols, key, False)
+
+	// Check whether we have everything
+	keys = dict_keys(symbols)
+	while (0 < list_len(keys)):
+		key = set_pop(keys)
+		if (bool_not(symbols[key])):
+			if (bool_not(bool_or(key == "output", key == "input"))):
+				return "ERROR: undefined symbol " + key
+
+	return "OK"
+
+Void function link_and_load(root : Element, main_function : String, objs : Element):
+	String obj
+	Element func
+	Element main_f
+	String result
+
+	result = check_symbols(root, main_function, objs)
+	output(result)
+
+	if (result == "OK"):
+		// Symbols verified OK, start execution
+		// Call all initializers in turn
+		while (0 < list_len(objs)):
+			obj = set_pop(objs)
+			func = root[obj]["initializers"]
+			exec(func)
+
+		// Resolve the main function, which should now be in (global) scope, and execute it
+		main_f = resolve(main_function)
+		main_f()
+	return

+ 21 - 22
bootstrap/conformance_scd.alc

@@ -129,14 +129,14 @@ String function conformance_scd(model : Element):
 			log((("Check " + model_name) + " : ") + type_name)
 
 			if (bool_not(dict_in_node(typing, element))):
-				return "Model has no type specified: " + 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)))):
-				return "Type of element not in specified metamodel: " + 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_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))
@@ -145,10 +145,10 @@ String function conformance_scd(model : Element):
 				dst_metamodel = reverseKeyLookup(metamodel["model"], read_edge_dst(dict_read_node(typing, element)))
 
 				if (bool_not(is_nominal_instance(model, src_model, src_metamodel))):
-					return "Source of model edge not typed by source of type: " + model_name
+					return "Source of model edge not typed by source of type: " + model_info(model, model_name)
 
 				if (bool_not(is_nominal_instance(model, dst_model, dst_metamodel))):
-					return "Destination of model edge not typed by source of type: " + model_name
+					return "Destination of model edge not typed by source of type: " + model_info(model, model_name)
 
 			// Check cardinality for all of our edges
 			//
@@ -157,9 +157,7 @@ String function conformance_scd(model : Element):
 			//
 			// First the incoming, so we are at B in the above figure
 			if (bool_not(dict_in(spo_cache, type_name))):
-				log("Fill SPO cache")
 				dict_add(spo_cache, type_name, selectPossibleOutgoing(metamodel, type_name, dict_keys(cardinalities)))
-				log("Filled SPO cache")
 
 			check_list = set_copy(spo_cache[type_name])
 			while (0 < list_len(check_list)):
@@ -171,23 +169,18 @@ String function conformance_scd(model : Element):
 						if (dict_in(cardinalities[check_type], "tlc")):
 							// A lower cardinality was defined at the target
 							if (integer_gt(cardinalities[check_type]["tlc"], instances)):
-								log("Instances: " + cast_i2s(instances))
-								log("Cardinalities: " + cast_i2s(cardinalities[check_type]["tuc"]))
-								log("Type: " + check_type)
-								return "Lower cardinality violation for outgoing edge at " + model_name
+								return "Lower cardinality violation for outgoing edge at " + model_info(model, model_name)
 						if (dict_in(cardinalities[check_type], "tuc")):
 							// An upper cardinality was defined at the target
 							if (integer_lt(cardinalities[check_type]["tuc"], instances)):
 								log("Instances: " + cast_i2s(instances))
 								log("Cardinalities: " + cast_i2s(cardinalities[check_type]["tuc"]))
 								log("Type: " + check_type)
-								return "Upper cardinality violation for outgoing edge at " + model_name
+								return "Upper cardinality violation for outgoing edge at " + model_info(model, model_name)
 
 			// Identical, but for outgoing, and thus for A in the figure
 			if (bool_not(dict_in(spi_cache, type_name))):
-				log("Fill SPI cache")
 				dict_add(spi_cache, type_name, selectPossibleIncoming(metamodel, type_name, dict_keys(cardinalities)))
-				log("Filled SPI cache")
 
 			check_list = set_copy(spi_cache[type_name])
 			while (0 < list_len(check_list)):
@@ -199,17 +192,11 @@ String function conformance_scd(model : Element):
 						if (dict_in(cardinalities[check_type], "slc")):
 							// A lower cardinality was defined at the source
 							if (integer_gt(cardinalities[check_type]["slc"], instances)):
-								log("Instances: " + cast_i2s(instances))
-								log("Cardinalities: " + cast_i2s(cardinalities[check_type]["tuc"]))
-								log("Type: " + check_type)
-								return "Lower cardinality violation for incoming edge at " + model_name
+								return "Lower cardinality violation for incoming edge at " + model_info(model, model_name)
 						if (dict_in(cardinalities[check_type], "suc")):
 							// An upper cardinality was defined at the source
 							if (integer_lt(cardinalities[check_type]["suc"], instances)):
-								log("Instances: " + cast_i2s(instances))
-								log("Cardinalities: " + cast_i2s(cardinalities[check_type]["tuc"]))
-								log("Type: " + check_type)
-								return "Upper cardinality violation for incoming edge at " + model_name
+								return "Upper cardinality violation for incoming edge at " + model_info(model, model_name)
 
 			Element constraint_function
 			constraint_function = read_attribute(metamodel, reverseKeyLookup(metamodel["model"], dict_read_node(typing, element)), "constraint")
@@ -276,3 +263,15 @@ Element function generate_bottom_type_mapping(model : Element):
 			dict_add(tm, elem, mm["Node"])
 
 	return model
+
+String function model_info(model : Element, name : String):
+	return name
+	// For more detailed information
+	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 + "\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])))
+	return result

+ 20 - 7
bootstrap/constructors.alc

@@ -8,13 +8,14 @@ Element while_stack = ?
 
 Action function construct_top():
 	String command
-	command = input()
-	if (command == "global"):
-		return construct_global()
-	elif (command == "funcdef"):
-		return construct_top_funcdef()
-	else:
-		log("ERROR: did not understand command " + cast_e2s(command))
+	while (True):
+		command = input()
+		if (command == "global"):
+			return construct_global()
+		elif (command == "funcdef"):
+			return construct_top_funcdef()
+		else:
+			log("ERROR: did not understand command " + cast_e2s(command))
 
 Action function construct_global():
 	Action this_element
@@ -284,6 +285,15 @@ Action function construct_function():
 	Element params
 	String arg_names_decl
 
+	log("Constructing function")
+	while (value_neq(input(), "funcdef")):
+		// We skip over everything that is not a funcdef, as these are all just definitions of global stuff
+		log("Skip over input!")
+
+	log("Reading name of function")
+	// Consume the name
+	input()
+
 	params = create_node()
 	nrParams = input()
 	counter = 0
@@ -301,4 +311,7 @@ Action function construct_function():
 	// Now add the body
 	dict_add(func, "body", construct_unknown())
 
+	// Consume the final 'false', to indicate that no additional code will come
+	input()
+
 	return func

+ 9 - 7
bootstrap/metamodels.alc

@@ -406,17 +406,19 @@ Element function initialize_bottom(location_bottom : String):
 	return ltm_bottom
 
 Element function create_metamodels():
-	if (bool_not(dict_in(dict_read(read_root(), "__hierarchy"), "models"))):
-		String location_SCD
-		String location_PN
-		String location_bottom
+	String location_SCD
+	String location_PN
+	String location_bottom
 
-		location_SCD = "models/SimpleClassDiagrams"
-		location_PN = "models/PetriNets"
-		location_bottom = "models/LTM_bottom"
+	location_SCD = "models/SimpleClassDiagrams"
+	location_PN = "models/PetriNets"
+	location_bottom = "models/LTM_bottom"
 
+	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"), "LTM_bottom"))):
 		initialize_bottom(location_bottom)
 
 	return dict_read(dict_read(read_root(), "__hierarchy"), "models")

File diff suppressed because it is too large
+ 1859 - 0
bootstrap/minimal.m


+ 18 - 0
bootstrap/object_operations.alc

@@ -163,3 +163,21 @@ String function print_dict(dict : Element):
 		result = result + cast_v2s(dict[key])
 		result = result + "\n"
 	return result
+
+String function readAssociationSource(model : Element, name : String):
+	return reverseKeyLookup(model["model"], read_edge_src(model["model"][name]))
+
+String function readAssociationDestination(model : Element, name : String):
+	return reverseKeyLookup(model["model"], read_edge_dst(model["model"][name]))
+
+String function followAssociation(model : Element, element_name : String, association_name : String):
+	Element assocs
+	String assoc
+	Element result
+
+	assocs = allOutgoingAssociationInstances(model, element_name, association_name)
+	result = create_node()
+	while (0 < list_len(assocs)):
+		set_add(result, readAssociationDestination(model, set_pop(assocs)))
+
+	return result

+ 11 - 0
bootstrap/primitives.alc

@@ -73,6 +73,7 @@ Integer function string_len(a: String) = ?primitives/string_len
 Element function deserialize(a: String) = ?primitives/deserialize
 Element function log(a: String) = ?primitives/log
 Element function read_root() = ?primitives/read_root
+Element function read_userroot() = ?primitives/read_userroot
 Boolean function is_physical_int(a: Element) = ?primitives/is_physical_int
 Boolean function is_physical_float(a: Element) = ?primitives/is_physical_float
 Boolean function is_physical_string(a: Element) = ?primitives/is_physical_string
@@ -155,3 +156,13 @@ String function string_substr(a: String, b: Integer, c: Integer):
 			return result
 	return result
 	
+Element function resolve(name : String):
+	// Could directly access it through introspection
+	// But seems safer to create some code and execute it...
+	Element user_root
+	user_root = read_userroot()
+	user_root = user_root["globals"][name]["value"]
+	return user_root
+
+Integer function integer_modulo(a : Integer, b : Integer):
+	return a - b * (a / b)

+ 26 - 0
bootstrap/random.alc

@@ -0,0 +1,26 @@
+include "primitives.alh"
+
+Integer seed = 1
+
+Float function random():
+	// Linear Congruential Generator
+	Integer a
+	Integer c
+	Integer m
+
+	// Parameters from Numerical Recipes
+	a = 1664525
+	c = 1013904223
+	m = 4294967296
+
+	// Do the generation and update the seed
+	seed = integer_modulo(a * seed + c, m)
+
+	// The seed is the new value
+	return seed / m
+
+Integer function random_interval(a : Integer, b : Integer):
+	return cast_f2i(random() * (b - a) + a)
+
+Element function random_choice(list : Element):
+	return read_edge_dst(read_out(list, random_interval(0, read_nr_out(list) - 1)))

+ 0 - 2
hybrid_server/classes/mvkcontroller.xml

@@ -59,8 +59,6 @@
                 if commands is None:
                     break
                 reply = [self.mvs_operations[command[0]](*(command[1]))[0] for command in commands]
-                if len(reply) == 1:
-                    reply = reply[0]
             ]]>
         </body>
     </method>

+ 0 - 151
integration/code/b2dc.txt

@@ -1,151 +0,0 @@
-'"global"'
-	0
-	'true'
-'"funcdef"'
-	0
-	'1'
-	1
-	'"declare"'
-		2
-		'true'
-	'"assign"'
-		'"resolve"'
-			2
-		'"const"'
-			'0'
-		'true'
-	'"declare"'
-		3
-		'true'
-	'"assign"'
-		'"resolve"'
-			3
-		'"call"'
-			'"deref"'
-				'"primitives/string_len"'
-			'1'
-			'"access"'
-				'"resolve"'
-					1
-			'false'
-		'true'
-	'"declare"'
-		4
-		'true'
-	'"assign"'
-		'"resolve"'
-			4
-		'"call"'
-			'"deref"'
-				'"primitives/integer_subtraction"'
-			'2'
-			'"access"'
-				'"resolve"'
-					3
-			'"const"'
-				'1'
-			'false'
-		'true'
-	'"declare"'
-		5
-		'true'
-	'"assign"'
-		'"resolve"'
-			5
-		'"const"'
-			'1'
-		'true'
-	'"while"'
-		'"call"'
-			'"deref"'
-				'"primitives/integer_gte"'
-			'2'
-			'"access"'
-				'"resolve"'
-					4
-			'"const"'
-				'0'
-			'false'
-		'"if"'
-			'"call"'
-				'"deref"'
-					'"primitives/string_eq"'
-				'2'
-				'"call"'
-					'"deref"'
-						'"primitives/string_get"'
-					'2'
-					'"access"'
-						'"resolve"'
-							1
-					'"access"'
-						'"resolve"'
-							4
-					'false'
-				'"const"'
-					'"1"'
-				'false'
-			'"assign"'
-				'"resolve"'
-					2
-				'"call"'
-					'"deref"'
-						'"primitives/integer_addition"'
-					'2'
-					'"access"'
-						'"resolve"'
-							2
-					'"access"'
-						'"resolve"'
-							5
-					'false'
-				'false'
-			'true'
-		'"assign"'
-			'"resolve"'
-				5
-			'"call"'
-				'"deref"'
-					'"primitives/integer_multiplication"'
-				'2'
-				'"access"'
-					'"resolve"'
-						5
-				'"const"'
-					'2'
-				'false'
-			'true'
-		'"assign"'
-			'"resolve"'
-				4
-			'"call"'
-				'"deref"'
-					'"primitives/integer_subtraction"'
-				'2'
-				'"access"'
-					'"resolve"'
-						4
-				'"const"'
-					'1'
-				'false'
-			'false'
-		'true'
-	'"return"'
-		'true'
-		'"access"'
-			'"resolve"'
-				2
-	'true'
-'"while"'
-	'"const"'
-		'true'
-	'"output"'
-		'"call"'
-			'"access"'
-				'"resolve"'
-					0
-			'1'
-			'"input"'
-			'false'
-		'false'
-	'false'

+ 0 - 326
integration/code/import_metamodel_cs.txt

@@ -1,326 +0,0 @@
-'"funcdef"'
-	3
-	'0'
-	'"declare"'
-		27
-		'true'
-	'"declare"'
-		28
-		'true'
-	'"assign"'
-		'"resolve"'
-			7
-		'"call"'
-			'"deref"'
-				'"primitives/create_node"'
-			'0'
-			'false'
-		'true'
-	'"assign"'
-		'"resolve"'
-			8
-		'"call"'
-			'"deref"'
-				'"primitives/create_node"'
-			'0'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"primitives/dict_add"'
-		'3'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"model"'
-		'"access"'
-			'"resolve"'
-				8
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_node"'
-		'2'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"Class"'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_value"'
-		'3'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__Type"'
-		'"const"'
-			'Type'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_value"'
-		'3'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__String"'
-		'"const"'
-			'String'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__Attribute_"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__Type"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__AttributeAttrs"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__Attribute_"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__Type"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__Attribute"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__Type"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__Name"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__Attribute"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__String"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"Association"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"Inheritance"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-		'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__inh_1"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Association"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'true'
-	'"call"'
-		'"deref"'
-			'"conformance/instantiate_bottom_edge"'
-			'4'
-		'"access"'
-			'"resolve"'
-				7
-		'"const"'
-			'"__inh_2"'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"__Attribute_"'
-			'false'
-		'"call"'
-			'"deref"'
-				'"primitives/dict_read"'
-			'2'
-			'"access"'
-				'"resolve"'
-					8
-			'"const"'
-				'"Class"'
-			'false'
-		'true'
-	'"declare"'
-		29
-		'true'
-	'"assign"'
-		'"resolve"'
-			9
-		'"call"'
-			'"deref"'
-				'"primitives/create_node"'
-			'0'
-			'false'
-		'true'

+ 20 - 9
integration/code/pn_interface.alc

@@ -6,6 +6,7 @@ include "conformance_scd.alh"
 include "io.alh"
 include "metamodels.alh"
 include "modelling.alh"
+include "compilation_manager.alh"
 
 Element function pn_operations():
 	Element ops
@@ -167,22 +168,28 @@ Element function model_loaded(model : Element):
 							dst_name = input()
 							if (dict_in(model["model"], dst_name)):
 								instantiate_link(model, mm_type_name, element_name, src_name, dst_name)
-								if (dict_in(model["model"], element_name)):
-									output("Instantiation successful!")
-								else:
-									output("Instantiation error!")
+								output("Instantiation successful!")
 							else:
 								output("Unknown destination; aborting")
 						else:
 							output("Unknown source; aborting")
 					else:
 						instantiate_node(model, mm_type_name, element_name)
-						if (dict_in(model["model"], element_name)):
-							output("Instantiation successful!")
-						else:
-							output("Instantiation error!")
+						output("Instantiation successful!")
 			else:
 				output("Unknown type specified; aborting")
+		elif (cmd == "set_inheritance"):
+			String inh_name
+
+			output("Which link in the metamodel is the inheritance link?")
+			inh_name = input()
+
+			if (dict_in(model["metamodel"]["model"], inh_name)):
+				dict_add(model, "inheritance", model["metamodel"]["model"][inh_name])
+				output("Set inheritance link!")
+			else:
+				output("Element not found in metamodel; aborting")
+
 		elif (cmd == "constrain"):
 			output("Element to constrain (empty for global)?")
 			String model_name
@@ -369,7 +376,7 @@ Element function model_loaded(model : Element):
 			specific_op = dict_read(pn_operations(), cmd)
 			specific_op(model)
 		else:
-			output("Unknown command; aborting")
+			output("Unknown command: " + cast_v2s(cmd))
 			output("Use command 'help' to get a list of available commands")
 
 Element function initial_prompt():
@@ -450,6 +457,10 @@ Element function initial_prompt():
 					output("Rename complete!")
 			else:
 				output("Model not found; aborting")
+		elif (command == "actions"):
+			output("Switching to compilation manager!")
+			compilation_manager()
+			output("Back in model manager!")
 		else:
 			output("Command not recognized, use 'help' for a list of possible commands")
 

+ 1 - 1
integration/test_binary2decimal.py

@@ -12,6 +12,6 @@ class TestBinary2Decimal(unittest.TestCase):
 
     def binary2decimal(self, mode):
         self.assertTrue(run_file(["binary_to_decimal.alc", "primitives.alc"],
-            ["1", "10", "11", "100", "001", "1100111101"],
+            ['"1"', '"10"', '"11"', '"100"', '"001"', '"1100111101"'],
             ["1", "2", "3", "4", "1", "829"],
             mode))

+ 3 - 0
integration/test_constructors_models.py

@@ -185,6 +185,8 @@ def add_constraints(model):
     return [
             '"model"',
             '"add_constraint"', model, '"Integer"',
+                '"funcdef"',
+                '"constraint"',
                 '2', model*100, model*100+1,
                     '"if"',
                         '"call"',
@@ -210,6 +212,7 @@ def add_constraints(model):
                             'true',
                                 '"const"', '"Integer instance is not an integer."',
                         'false',
+                    'false',
             '"exit"',
         ]
 

+ 1 - 1
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', '3', '4'],
             ["1", "2", "6", "24"],
             mode))

+ 1 - 1
integration/test_fibonacci.py

@@ -12,6 +12,6 @@ class TestFibonacci(unittest.TestCase):
 
     def fibonacci(self, mode):
         self.assertTrue(run_file(["fibonacci.alc", "primitives.alc"],
-            [1, 2, 3, 4],
+            ['1', '2', '3', '4'],
             ["1", "1", "2", "3"],
             mode))

+ 1 - 1
integration/test_fibonacci_smart.py

@@ -12,6 +12,6 @@ class TestFibonacciSmart(unittest.TestCase):
 
     def fibonacci_smart(self, mode):
         self.assertTrue(run_file(["fibonacci_smart.alc", "primitives.alc"],
-            [1, 2, 3, 4, 5, 6, 7, 8],
+            ['1', '2', '3', '4', '5', '6', '7', '8'],
             ["1", "1", "2", "3", "5", "8", "13", "21"],
             mode))

+ 2 - 2
integration/test_if_elif.py

@@ -12,7 +12,7 @@ class TestIfElif(unittest.TestCase):
 
     def if_elif_else(self, mode):
         self.assertTrue(run_file(["if_elif_else.alc", "primitives.alc"],
-            [-1,   10,  11,  0,   1,   0,   -100],
+            ['-1', '10', '11', '0', '1', '0', '-100'],
             ["-1", "1", "1", "0", "1", "0", "-1"],
             mode))
 
@@ -24,6 +24,6 @@ class TestIfElif(unittest.TestCase):
 
     def if_elif(self, mode):
         self.assertTrue(run_file(["if_elif.alc", "primitives.alc"],
-                                 [-1, 10, 11, 0, 1, 0, -100],
+                                 ['-1', '10', '11', '0', '1', '0', '-100'],
                                  ["-1", "1", "1", "0", "1", "0", "-1"],
                                  mode))

+ 1 - 1
integration/test_leap_year.py

@@ -12,6 +12,6 @@ class TestLeapYear(unittest.TestCase):
 
     def leap_year(self, mode):
         self.assertTrue(run_file(["leap_year.alc", "primitives.alc"],
-            [  2016,    2015,    2014,    2013,   2012,    2001,    2000,    1999],
+            ['2016', '2015', '2014', '2013', '2012', '2001', '2000', '1999'],
             ["True", "False", "False", "False", "True", "False", "False", "False"],
             mode))

+ 202 - 97
integration/test_pn_interface.py

@@ -1,14 +1,19 @@
 import unittest
 
-from utils import run_file
+from utils import run_file, get_constructor
+
+set_inheritance = [
+        "Which link in the metamodel is the inheritance link?",
+        "Set inheritance link!",
+    ]
 
 do_instantiate_simple = [
-            "new", "PetriNets", "abc",
-            "instantiate", "Transition", "t1",
-            "instantiate", "Place", "p1", "attr_add", "p1", "tokens", 5,
-            "instantiate", "Place", "p2", "attr_add", "p2", "tokens", 0,
-            "instantiate", "P2T", "p2t", "p1", "t1", "attr_add", "p2t", "weight", 2,
-            "instantiate", "T2P", "t2p", "t1", "p2", "attr_add", "t2p", "weight", 1]
+            '"new"', '"PetriNets"', '"abc"',
+            '"instantiate"', '"Transition"', '"t1"',
+            '"instantiate"', '"Place"', '"p1"', '"attr_add"', '"p1"', '"tokens"', '5',
+            '"instantiate"', '"Place"', '"p2"', '"attr_add"', '"p2"', '"tokens"', '0',
+            '"instantiate"', '"P2T"', '"p2t"', '"p1"', '"t1"', '"attr_add"', '"p2t"', '"weight"', '2',
+            '"instantiate"', '"T2P"', '"t2p"', '"t1"', '"p2"', '"attr_add"', '"t2p"', '"weight"', '1']
 
 instantiate_node = ["Type to instantiate?",
                     "Name of new element?",
@@ -28,6 +33,7 @@ all_files = [   "pn_interface.alc",
                 "metamodels.alc",
                 "constructors.alc",
                 "modelling.alc",
+                "compilation_manager.alc",
             ]
 
 greeting =          ["Welcome to the Model Management Interface, running live on the Modelverse!",
@@ -148,17 +154,17 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_manage(self, mode):
         self.assertTrue(run_file(all_files,
-            ["list",
-             "new", "PetriNets", "abc", "exit",
-             "list",
-             "new", "PetriNets", "def", "exit",
-             "list",
-             "delete", "def",
-             "list",
-             "rename", "abc", "a",
-             "list",
-             "delete", "a",
-             "list",
+            ['"list"',
+             '"new"', '"PetriNets"', '"abc"', '"exit"',
+             '"list"',
+             '"new"', '"PetriNets"', '"def"', '"exit"',
+             '"list"',
+             '"delete"', '"def"',
+             '"list"',
+             '"rename"', '"abc"', '"a"',
+             '"list"',
+             '"delete"', '"a"',
+             '"list"',
              ],
             init + \
                 list_menu([]) + prompt + \
@@ -177,7 +183,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_new_reload(self, mode):
         self.assertTrue(run_file(all_files,
-            ["new", "PetriNets", "abc", "exit", "load", "abc"],
+            ['"new"', '"PetriNets"', '"abc"', '"exit"', '"load"', '"abc"'],
             init + new + loaded + prompt + load + loaded,
             mode))
 
@@ -189,14 +195,14 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_instantiate_place(self, mode):
         self.assertTrue(run_file(all_files,
-            ["new", "PetriNets", "abc",
-            "instantiate", "Place", "p1",
-            "attr_add", "p1", "tokens", 5,
-            "list",
-            "read", "p1",
-            "instantiate", "Transition", "t1",
-            "list",
-            "read", "t1"],
+            ['"new"', '"PetriNets"', '"abc"',
+            '"instantiate"', '"Place"', '"p1"',
+            '"attr_add"', '"p1"', '"tokens"', '5',
+            '"list"',
+            '"read"', '"p1"',
+            '"instantiate"', '"Transition"', '"t1"',
+            '"list"',
+            '"read"', '"t1"'],
             init + new + loaded + \
                 instantiate_node + prompt + \
                 attr_add + prompt + \
@@ -216,11 +222,11 @@ class TestPetrinetInterface(unittest.TestCase):
     def pn_interface_instantiate_arcs(self, mode):
         self.assertTrue(run_file(all_files,
             do_instantiate_simple + [
-                    "read", "p1",
-                    "read", "p2",
-                    "read", "t1",
-                    "read", "p2t",
-                    "read", "t2p",
+                    '"read"', '"p1"',
+                    '"read"', '"p2"',
+                    '"read"', '"t1"',
+                    '"read"', '"p2t"',
+                    '"read"', '"t2p"',
                 ],
             did_instantiate_simple + \
                 read_node("p1", "Place", [], [("tokens", "Natural", 5)]) + prompt + \
@@ -238,7 +244,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_enabled(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["enabled"],
+            do_instantiate_simple + ['"enabled"'],
             did_instantiate_simple + enabled(["t1"]) + prompt,
             mode))
 
@@ -250,7 +256,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_fire(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["fire", "t1"],
+            do_instantiate_simple + ['"fire"', '"t1"'],
             did_instantiate_simple + fire([("p1", 3), ("p2", 1)]) + prompt,
             mode))
 
@@ -262,7 +268,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_OK(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["verify"],
+            do_instantiate_simple + ['"verify"'],
             did_instantiate_simple + ["OK"], mode))
 
     def test_po_pn_interface_verify_fail_tokens(self):
@@ -273,7 +279,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_fail_tokens(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["modify", "p1", "tokens", -5, "verify"],
+            do_instantiate_simple + ['"modify"', '"p1"', '"tokens"', '-5', '"verify"'],
             did_instantiate_simple + modify + prompt + verify_fail_tokens + prompt, mode))
 
     def test_po_pn_interface_verify_fail_weight(self):
@@ -284,7 +290,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_fail_weight(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["modify", "p2t", "weight", -2, "verify"],
+            do_instantiate_simple + ['"modify"', '"p2t"', '"weight"', '-2', '"verify"'],
             did_instantiate_simple + modify + prompt + verify_fail_weight + prompt, mode))
 
     def test_po_pn_interface_verify_fail_structure(self):
@@ -295,10 +301,10 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_fail_structure(self, mode):
         self.assertTrue(run_file(all_files,
-            ["new", "PetriNets", "abc",
-            "instantiate", "Transition", "t1",
-            "instantiate", "Place", "p1", "attr_add", "p1", "tokens", 5,
-            "instantiate", "P2T", "p2t", "t1", "p1", "attr_add", "p2t", "weight", 2, "verify"],
+            ['"new"', '"PetriNets"', '"abc"',
+            '"instantiate"', '"Transition"', '"t1"',
+            '"instantiate"', '"Place"', '"p1"', '"attr_add"', '"p1"', '"tokens"', '5',
+            '"instantiate"', '"P2T"', '"p2t"', '"t1"', '"p1"', '"attr_add"', '"p2t"', '"weight"', '2', '"verify"'],
             init + new + loaded + \
                 instantiate_node + prompt + \
                 instantiate_node + prompt + attr_add + prompt + \
@@ -314,7 +320,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_types(self, mode):
         self.assertTrue(run_file(all_files,
-            ["new", "PetriNets", "abc", "types"],
+            ['"new"', '"PetriNets"', '"abc"', '"types"'],
             init + new + loaded + list_types([("Place", "Class"), ("Transition", "Class"), ("P2T", "Association"), ("T2P", "Association"), ("Natural", "Class")]),
             mode))
 
@@ -326,10 +332,10 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_modify_place(self, mode):
         self.assertTrue(run_file(all_files,
-            ["new", "PetriNets", "abc",
-                "instantiate", "Place", "p1", "attr_add", "p1", "tokens", 5,
-                "read", "p1",
-                "modify", "p1", "tokens", 1, "read", "p1"],
+            ['"new"', '"PetriNets"', '"abc"',
+                '"instantiate"', '"Place"', '"p1"', '"attr_add"', '"p1"', '"tokens"', '5',
+                '"read"', '"p1"',
+                '"modify"', '"p1"', '"tokens"', '1', '"read"', '"p1"'],
             init + new + loaded + \
                 instantiate_node + prompt + attr_add + prompt + \
                 read_node("p1", "Place", [], [("tokens", "Natural", 5)]) + prompt + \
@@ -345,7 +351,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_fail_attr_lower_cardinality(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["instantiate", "Place", "p999", "verify"],
+            do_instantiate_simple + ['"instantiate"', '"Place"', '"p999"', '"verify"'],
             did_instantiate_simple + instantiate_node + prompt + ["Lower cardinality violation for outgoing edge at p999"] + prompt,
             mode))
 
@@ -357,7 +363,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_fail_attr_upper_cardinality(self, mode):
         self.assertTrue(run_file(all_files,
-            do_instantiate_simple + ["attr_add", "p1", "tokens", 5, "verify"],
+            do_instantiate_simple + ['"attr_add"', '"p1"', '"tokens"', '5', '"verify"'],
             did_instantiate_simple + attr_add + prompt + ["Upper cardinality violation for outgoing edge at p1"] + prompt,
             mode))
 
@@ -369,12 +375,12 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_natural(self, mode):
         self.assertTrue(run_file(all_files,
-            ["new", "PetriNets", "abc",
-            "instantiate", "Place", "p1",
-            "attr_add", "p1", "tokens", -5,
-            "attr_del", "p1", "tokens",
-            "attr_add", "p1", "tokens", 4,
-            "verify"],
+            ['"new"', '"PetriNets"', '"abc"',
+            '"instantiate"', '"Place"', '"p1"',
+            '"attr_add"', '"p1"', '"tokens"', '-5',
+            '"attr_del"', '"p1"', '"tokens"',
+            '"attr_add"', '"p1"', '"tokens"', '4',
+            '"verify"'],
             init + new + loaded + \
             instantiate_node + prompt + \
             attr_add + prompt + \
@@ -391,7 +397,7 @@ class TestPetrinetInterface(unittest.TestCase):
 
     def pn_interface_verify_PN_OK(self, mode):
         self.assertTrue(run_file(all_files,
-            ["load", "PetriNets", "verify"],
+            ['"load"', '"PetriNets"', '"verify"'],
             init + load + loaded + ["OK"], mode))
 
     def test_po_rpgame(self):
@@ -401,48 +407,147 @@ class TestPetrinetInterface(unittest.TestCase):
         self.rpgame("CO")
 
     def rpgame(self, mode):
+
+        constraint_code = \
+            """
+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"
+            """
+
+        constructors = get_constructor(constraint_code)
+        print(constructors)
+
         self.assertTrue(run_file(all_files,
-            ["new", "SimpleClassDiagrams", "RPGame",
-                "instantiate", "Class", "Scene",
-                "instantiate", "Class", "Tile",
-                "instantiate", "Class", "Item",
-                "instantiate", "Class", "Goal",
-                "instantiate", "Class", "Character",
-                "instantiate", "Class", "Hero",
-                "instantiate", "Class", "String",
-                "instantiate", "Association", "scene_name", "Scene", "String",
-                "instantiate", "Association", "scene_has_tiles", "Scene", "Tile",
-                "instantiate", "Association", "tile_left", "Tile", "Tile",
-                "instantiate", "Association", "tile_right", "Tile", "Tile",
-                "instantiate", "Association", "tile_top", "Tile", "Tile",
-                "instantiate", "Association", "tile_bottom", "Tile", "Tile",
-                "instantiate", "Association", "character_on", "Character", "Tile",
-                "instantiate", "Association", "item_on", "Item", "Tile",
-                "instantiate", "Inheritance", "hero_is_character", "Hero", "Character",
-                "instantiate", "Inheritance", "goal_is_item", "Goal", "Item",
-                "attr_add", "Scene", "lower_cardinality", 1,
-                "attr_add", "Scene", "upper_cardinality", 1,
-                "attr_add", "Goal", "lower_cardinality", 1,
-                "attr_add", "scene_has_tiles", "source_lower_cardinality", 1,
-                "attr_add", "scene_has_tiles", "source_upper_cardinality", 1,
-                "attr_add", "scene_has_tiles", "target_lower_cardinality", 1,
-                "attr_add", "scene_name", "target_lower_cardinality", 1,
-                "attr_add", "scene_name", "target_upper_cardinality", 1,
-                "attr_add", "item_on", "target_lower_cardinality", 1,
-                "attr_add", "item_on", "target_upper_cardinality", 1,
-                "attr_add", "item_on", "source_upper_cardinality", 1,
-                "attr_add", "character_on", "target_lower_cardinality", 1,
-                "attr_add", "character_on", "target_upper_cardinality", 1,
-                "attr_add", "character_on", "source_upper_cardinality", 1,
-                "attr_add", "tile_left", "source_upper_cardinality", 1,
-                "attr_add", "tile_left", "target_upper_cardinality", 1,
-                "attr_add", "tile_right", "source_upper_cardinality", 1,
-                "attr_add", "tile_right", "target_upper_cardinality", 1,
-                "attr_add", "tile_top", "source_upper_cardinality", 1,
-                "attr_add", "tile_top", "target_upper_cardinality", 1,
-                "attr_add", "tile_bottom", "source_upper_cardinality", 1,
-                "attr_add", "tile_bottom", "target_upper_cardinality", 1,
-                "verify",
+            ['"new"', '"SimpleClassDiagrams"', '"RPGame"',
+                '"set_inheritance"', '"Inheritance"',
+                '"instantiate"', '"Class"', '"Scene"',
+                '"instantiate"', '"Class"', '"Tile"',
+                '"instantiate"', '"Class"', '"Item"',
+                '"instantiate"', '"Class"', '"Goal"',
+                '"instantiate"', '"Class"', '"Character"',
+                '"instantiate"', '"Class"', '"Hero"',
+                '"instantiate"', '"Association"', '"scene_has_tiles"', '"Scene"', '"Tile"',
+                '"instantiate"', '"Association"', '"tile_left"', '"Tile"', '"Tile"',
+                '"instantiate"', '"Association"', '"tile_right"', '"Tile"', '"Tile"',
+                '"instantiate"', '"Association"', '"tile_top"', '"Tile"', '"Tile"',
+                '"instantiate"', '"Association"', '"tile_bottom"', '"Tile"', '"Tile"',
+                '"instantiate"', '"Association"', '"character_on"', '"Character"', '"Tile"',
+                '"instantiate"', '"Association"', '"item_on"', '"Item"', '"Tile"',
+                '"instantiate"', '"Inheritance"', '"hero_is_character"', '"Hero"', '"Character"',
+                '"instantiate"', '"Inheritance"', '"goal_is_item"', '"Goal"', '"Item"',
+                '"attr_add"', '"Scene"', '"lower_cardinality"', '1',
+                '"attr_add"', '"Scene"', '"upper_cardinality"', '1',
+                '"attr_add"', '"Goal"', '"lower_cardinality"', '1',
+                '"attr_add"', '"scene_has_tiles"', '"source_lower_cardinality"', '1',
+                '"attr_add"', '"scene_has_tiles"', '"source_upper_cardinality"', '1',
+                '"attr_add"', '"scene_has_tiles"', '"target_lower_cardinality"', '1',
+                '"attr_add"', '"item_on"', '"target_lower_cardinality"', '1',
+                '"attr_add"', '"item_on"', '"target_upper_cardinality"', '1',
+                '"attr_add"', '"item_on"', '"source_upper_cardinality"', '1',
+                '"attr_add"', '"character_on"', '"target_lower_cardinality"', '1',
+                '"attr_add"', '"character_on"', '"target_upper_cardinality"', '1',
+                '"attr_add"', '"character_on"', '"source_upper_cardinality"', '1',
+                '"attr_add"', '"tile_left"', '"source_upper_cardinality"', '1',
+                '"attr_add"', '"tile_left"', '"target_upper_cardinality"', '1',
+                '"attr_add"', '"tile_right"', '"source_upper_cardinality"', '1',
+                '"attr_add"', '"tile_right"', '"target_upper_cardinality"', '1',
+                '"attr_add"', '"tile_top"', '"source_upper_cardinality"', '1',
+                '"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"',
+            ] + constructors + ['"verify"'] + ['"exit"'] + [
+                '"new"', '"RPGame"', '"my_game"',
+                '"instantiate"', '"Scene"', '"scene"',
+                '"instantiate"', '"Hero"', '"Link"',
+                '"instantiate"', '"Goal"', '"goal"',
+                '"instantiate"', '"Tile"', '"tile_00"',
+                '"instantiate"', '"Tile"', '"tile_01"',
+                '"instantiate"', '"Tile"', '"tile_10"',
+                '"instantiate"', '"Tile"', '"tile_11"',
+                '"instantiate"', '"scene_has_tiles"', '""', '"scene"', '"tile_00"',
+                '"instantiate"', '"scene_has_tiles"', '""', '"scene"', '"tile_01"',
+                '"instantiate"', '"scene_has_tiles"', '""', '"scene"', '"tile_10"',
+                '"instantiate"', '"scene_has_tiles"', '""', '"scene"', '"tile_11"',
+                '"instantiate"', '"character_on"', '""',  '"Link"', '"tile_00"',
+                '"instantiate"', '"item_on"', '""', '"goal"', '"tile_11"',
+                '"instantiate"', '"tile_left"', '""', '"tile_01"', '"tile_00"',
+                '"instantiate"', '"tile_left"', '""', '"tile_11"', '"tile_10"',
+                '"instantiate"', '"tile_right"', '""', '"tile_00"', '"tile_01"',
+                '"instantiate"', '"tile_right"', '""', '"tile_10"', '"tile_11"',
+                '"instantiate"', '"tile_top"', '""', '"tile_10"', '"tile_00"',
+                '"instantiate"', '"tile_top"', '""', '"tile_11"', '"tile_01"',
+                '"instantiate"', '"tile_bottom"', '""', '"tile_00"', '"tile_10"',
+                '"instantiate"', '"tile_bottom"', '""', '"tile_01"', '"tile_11"',
+                '"verify"',
             ],
-            init + new + loaded + (instantiate_node + prompt) * 7 + (instantiate_edge + prompt) * 10 + (attr_add + prompt) * 22 + ["OK"] + prompt,
+            init + new + loaded + \
+                set_inheritance + prompt + \
+                (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!"] + \
+                prompt + \
+                ["OK"] + \
+                prompt + prompt + new + loaded + \
+                (instantiate_node + prompt) * 7 + \
+                (instantiate_edge + prompt) * 14 + \
+                ["OK"],
             mode))

+ 1 - 1
integration/test_power.py

@@ -12,5 +12,5 @@ class TestPower(unittest.TestCase):
 
     def power(self, mode):
         self.assertTrue(run_file(["power.alc", "primitives.alc"],
-            [(1, 0), (2, 1), (5, 0), (2, 2), (3, 2), (10, 2), (10, 10)],
+            ['1', '0', '2', '1', '5', '0', '2', '2', '3', '2', '10', '2', '10', '10'],
             ["1", "2", "1", "4", "9", "100", "10000000000"], mode))

+ 1 - 1
integration/test_remainder.py

@@ -12,5 +12,5 @@ class TestRemainder(unittest.TestCase):
 
     def remainder(self, mode):
         self.assertTrue(run_file(["remainder.alc", "primitives.alc"],
-            [(1, 2), (20, 2), (99, 100), (17, 3)],
+            ['1', '2', '20', '2', '99', '100', '17', '3'],
             ["1", "0", "99", "2"], mode))

+ 1 - 1
integration/test_revert.py

@@ -12,6 +12,6 @@ class TestRevert(unittest.TestCase):
 
     def revert(self, mode):
         self.assertTrue(run_file(["revert.alc", "primitives.alc"],
-            ["abc", "defghi", "This is a very simple test case!", "abccba"],
+            ['"abc"', '"defghi"', '"This is a very simple test case!"', '"abccba"'],
             ["cba", "ihgfed", "!esac tset elpmis yrev a si sihT", "abccba"],
             mode))

+ 52 - 11
integration/utils.py

@@ -11,6 +11,9 @@ import subprocess
 import signal
 import random
 
+sys.path.append("interface/HUTN")
+from hutn_compiler.compiler import main as do_compile
+
 username = "test_user"
 parallel_push = True
 
@@ -35,12 +38,6 @@ def getFreePort():
             # Didn't find a duplicate
             return port
 
-def serialize(value):
-    if isinstance(value, str):
-        return '"%s"' % value
-    else:
-        return str(value)
-
 def execute(scriptname, parameters=[], wait=False):
     if os.name not in ["nt", "posix"]:
         # Stop now, as we would have no clue on how to kill its subtree
@@ -143,19 +140,54 @@ def run_file(files, parameters, expected, mode):
                 raise Exception("Linking error")
 
         # Send in the actual request and wait for replies
+        var_list = {}
         data = []
+        got_output = []
         for p in parameters:
-            if isinstance(p, tuple):
-                for v in p:
-                    data.append(["V", serialize(v)])
+            if isinstance(p, int):
+                if p not in var_list:
+                    data = flush_data(address, data)
+                    
+                    proc.poll()
+                    if proc.returncode is not None:
+                        # Modelverse has already terminated, which isn't a good sign!
+                        return False
+
+                    while 1:
+                        val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=120).read()
+                        l, r = val.split("&", 1)
+                        if l.startswith("id"):
+                            id_str = l
+                            val_str = r
+                        else:
+                            id_str = r
+                            val_str = l
+                        id_val = id_str.split("=", 1)[1]
+                        val_val = val_str.split("=", 1)[1]
+
+                        if val_val == "None":
+                            var_list[p] = id_val
+                            break
+                        else:
+                            got_output.append(val)
+                    continue
+                else:
+                    val = var_list[p]
+                    t = "R"
             else:
-                data.append(["V", serialize(p)])
+                val = p
+                t = "V"
+            data.append([t, val])
+        data = flush_data(address, data)
         flush_data(address, data)
         
         for e in expected:
             c = len(e) if isinstance(e, set) else 1
             for _ in range(c):
-                val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=240).read()
+                if got_output:
+                    val = got_output.pop(0)
+                else:
+                    val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=240).read()
 
                 if proc.returncode is not None:
                     # Modelverse has already terminated, which isn't a good sign!
@@ -294,3 +326,12 @@ def run_barebone(parameters, expected, interface="0", timeout=False, wait=False,
         return not timeout
     finally:
         kill(proc)
+
+def get_constructor(code):
+    with open("__constraint.al", "w") as f:
+        f.write(code)
+        f.flush()
+
+    constructors = do_compile("__constraint.al", "interface/HUTN/grammars/actionlanguage.g", "CS")
+
+    return constructors

+ 9 - 81
interface/HUTN/hutn_compiler/linker.py

@@ -14,92 +14,20 @@ def link(address, username, objects):
     users = {}
     data = []
 
-    definers["main"] = None
+    data.append(("V", '3'))
+    data.append(("V", '"link_and_load"'))
     for obj in objects:
-        data.append(("V", '3'))
-        data.append(("V", '"read_symbols"'))
         data.append(("V", '"%s"' % obj))
+    data.append(("V", '""'))
 
-    data = flush_data(address, data, username)
-
-    for obj in objects:
-        print("[SYMB] %s" % (obj))
-        v = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username}))).read()
-        lst = v.rsplit("=", 1)[1]
-        lst = lst.split("\n")
-        print("Split in " + str(lst))
-        for e in lst:
-            print("Check " + str(e))
-            if len(e) > 1:
-                name, defined = e.rsplit(":", 1)
-                if defined == "1":
-                    if definers.get(name, None):
-                        raise Exception("Double definition for symbol %s\nDefined in %s\nDefined in %s" % (name, definers[name], obj))
-                    definers[name] = obj
-                else:
-                    users.setdefault(name, []).append(obj)
-                    if name not in definers:
-                        definers[name] = None
-        print("Finished list!")
-
-    # Check for undefined symbols with this linking set
-    for symbol in definers:
-        if definers[symbol] is None:
-            if symbol not in ["input", "output"]:
-                # Some symbols are built-ins which only look like functions
-                raise Exception("Undefined symbol %s.\nUsed by modules:\n\t%s" % (symbol, "\n\t".join(users[symbol])))
-
-    # Ok, we know that all symbols can be defined with this set of files, now link their initializers together
-    initializers = []
-    for obj in objects:
-        data.append(("V", '3'))
-        data.append(("V", '"read_initializers"'))
-        data.append(("V", '"%s"' % obj))
+    # Call the main function
+    data.append(("V", '"main"'))
 
     data = flush_data(address, data, username)
-
-    for obj in objects:
-        print("[LINK] %s" % (obj))
-        v = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username}))).read()
-        start = str(v.split("&", 1)[0].split("=")[1])
-        initializers.append(start)
-
-    # Bind all initializers together
-    if definers:
-        print("[LOAD] %s:main()" % definers["main"])
-    else:
-        print("[LOAD] main()")
-
-    # Set interface to constructors
-    commands = [("V", '1')]
-
-    # Link all initializers together
-    for init in initializers:
-        commands.extend([
-                ("V", '"call"'),
-                    ("V", '"access"'),
-                        ("V", '"resolve"'),
-                            ("V", '"exec"'),
-                    ("V", '1'),
-                    ("V", '"const"'),
-                        ("R", str(init)),
-                    ("V", 'true'),
-            ])
-
-    # Load main function
-    commands.extend([
-                ("V", '"return"'),
-                    ("V", 'true'),
-                    ("V", '"call"'),
-                        ("V", '"access"'),
-                            ("V", '"resolve"'),
-                                ("V", '"main"'),
-                        ("V", '0'),
-                        ("V", 'false'),
-            ])
-
-    import json
-    urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "data": json.dumps(commands), "username": username}))).read()
+    v = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username}))).read()
+    if "OK" not in v:
+        print(v)
+        raise Exception("Linking error")
 
 if __name__ == "__main__":
     if len(sys.argv) == 1:

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

@@ -0,0 +1 @@
+Void function compilation_manager()

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

@@ -4,3 +4,4 @@ Boolean function is_nominal_subtype(metamodel : Element, subclass : String, supe
 Element function conformance_scd(model: Element)
 Element function set_model_constraints(model: Element, func: Element)
 Element function generate_bottom_type_mapping(model: Element)
+Element function set_copy(a : Element)

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

@@ -7,3 +7,6 @@ Element function getAttributeList(model: Element, element: String)
 Element function getInstantiatableAttributes(model: Element, element: String)
 String function reverseKeyLookup(a: Element, b: Element)
 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)

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

@@ -54,6 +54,7 @@ Integer function integer_addition(a: Integer, b: Integer)
 Integer function integer_subtraction(a: Integer, b: Integer) 
 Integer function integer_multiplication(a: Integer, b: Integer) 
 Integer function integer_division(a: Integer, b: Integer) 
+Integer function integer_modulo(a: Integer, b: Integer) 
 Boolean function integer_gt(a: Integer, b: Integer) 
 Boolean function integer_gte(a: Integer, b: Integer) 
 Boolean function integer_lt(a: Integer, b: Integer) 
@@ -79,6 +80,7 @@ Boolean function string_startswith(a: String, b: String)
 Element function deserialize(a: String) 
 String function log(a: String)
 Element function read_root()
+Element function read_userroot()
 Element function input()
 Element function output(a : Element)
 Boolean function is_physical_int(a : Element)
@@ -89,3 +91,4 @@ Boolean function is_physical_boolean(a : Element)
 Boolean function has_value(a : Element)
 
 Element function exec(a : Element)
+Element function resolve(var_name : String)

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

@@ -0,0 +1,3 @@
+Float function random()
+Integer function random_interval(a : Integer, b : Integer)
+Element function random_choice(list : Element)

+ 115 - 112
kernel/modelverse_kernel/compiled.py

@@ -1,40 +1,34 @@
 from modelverse_kernel.primitives import PrimitiveFinished
 
 def reverseKeyLookup(a, b, **remainder):
-    edges = yield [("RO", [a])]
+    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]])]
+            outgoing, = yield [("RO", [edges[i]])]
+            result, = yield [("RE", [outgoing[0]])]
             raise PrimitiveFinished(result[1])
 
-    result = yield [("CNV", ["(unknown: %s)" % b])]
+    result, = yield [("CNV", ["(unknown: %s)" % b])]
     raise PrimitiveFinished(result)
 
 def read_attribute(a, b, c, **remainder):
-    def make_list(v, l):
-        return [v] if l else v
-
     model_dict, b_val, c_val, type_mapping = \
                     yield [("RD", [a, "model"]),
                            ("RV", [b]),
                            ("RV", [c]),
                            ("RD", [a, "type_mapping"]),
                            ]
-    model_instance = \
+    model_instance, = \
                     yield [("RD", [model_dict, b_val])]
-    edges =         yield [("RO", [model_instance])]
+    edges, =        yield [("RO", [model_instance])]
     edge_types =    yield [("RDN", [type_mapping, i]) for i in edges]
-    edge_types = make_list(edge_types, len(edges) == 1)
     type_edge_val = yield [("RE", [i]) for i in edge_types]
-    type_edge_val = make_list(type_edge_val, len(edges) == 1)
 
     src_nodes = set([i[0] for i in type_edge_val])
 
     found_edges =   yield [("RDE", [i, c_val]) for i in src_nodes]
-    found_edges = make_list(found_edges, len(src_nodes) == 1)
 
     for e1 in found_edges:
         if e1 is not None:
@@ -43,36 +37,36 @@ def read_attribute(a, b, c, **remainder):
                 if e1 == e2:
                     # The instance of this edge is the one we want!
                     edge = edges[i]
-                    edge_val = yield [("RE", [edge])]
+                    edge_val, = yield [("RE", [edge])]
                     result = edge_val[1]
                     raise PrimitiveFinished(result)
     else:
-        result = yield [("RR", [])]
+        result, = yield [("RR", [])]
         raise PrimitiveFinished(result)
 
     raise Exception("Error in reading edge!")
 
 def precompute_cardinalities(a, **remainder):
-    result =        yield [("CN", [])]
+    result, =       yield [("CN", [])]
 
     # Read out all edges from the metamodel
-    a =             yield [("RD", [a, "metamodel"])]
-    model_dict =    yield [("RD", [a, "model"])]
-    model_keys =    yield [("RDK", [model_dict])]
-    type_mapping =  yield [("RD", [a, "type_mapping"])]
-    elems =         yield [("RDN", [model_dict, k]) for k in model_keys]
-    model_keys_str= yield [("RV", [i]) for i in model_keys]
-    elem_to_name =  dict(zip(elems, model_keys_str))
-    edges =         yield [("RE", [i]) for i in elems]
+    a, =             yield [("RD", [a, "metamodel"])]
+    model_dict, =    yield [("RD", [a, "model"])]
+    model_keys, =    yield [("RDK", [model_dict])]
+    type_mapping, =  yield [("RD", [a, "type_mapping"])]
+    elems  =         yield [("RDN", [model_dict, k]) for k in model_keys]
+    model_keys_str = yield [("RV", [i]) for i in model_keys]
+    elem_to_name =   dict(zip(elems, model_keys_str))
+    edges =          yield [("RE", [i]) for i in elems]
     elems = [elems[i] for i, edge_val in enumerate(edges) if edge_val is not None]
     # Now we have all edges in the metamodel
 
     # Read out the type of the Association defining all cardinalities
-    metamodel =     yield [("RD", [a, "metamodel"])]
-    metametamodel = yield [("RD", [metamodel, "metamodel"])]
-    metametamodel_dict = \
+    metamodel, =     yield [("RD", [a, "metamodel"])]
+    metametamodel, = yield [("RD", [metamodel, "metamodel"])]
+    metametamodel_dict, = \
                     yield [("RD", [metametamodel, "model"])]
-    assoc =         yield [("RD", [metametamodel_dict, "Association"])]
+    assoc, =         yield [("RD", [metametamodel_dict, "Association"])]
     slc, suc, tlc, tuc = \
                     yield [("RDE", [assoc, "source_lower_cardinality"]),
                            ("RDE", [assoc, "source_upper_cardinality"]),
@@ -98,7 +92,8 @@ def precompute_cardinalities(a, **remainder):
             continue
         
         # Found a link, so add it
-        source, destination = yield [("RE", [elems[i]])]
+        srcdst, = yield [("RE", [elems[i]])]
+        source, destination = srcdst
         # The edge gives the "source" the cardinality found in "destination"
         cardinalities.setdefault(elem_to_name[source], {})[t] = destination
 
@@ -115,21 +110,19 @@ def precompute_cardinalities(a, **remainder):
     raise PrimitiveFinished(result)
 
 def set_copy(a, **remainder):
-    b =         yield [("CN", [])]
-    links =     yield [("RO", [a])]
+    b, =         yield [("CN", [])]
+    links, =     yield [("RO", [a])]
     exp_links = yield [("RE", [i]) for i in links]
-    if len(links) == 1:
-        exp_links = [exp_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"])]
-    mm_dict =   yield [("RD", [metamodel, "model"])]
-    typing =    yield [("RD", [a, "type_mapping"])]
-    elem_keys = yield [("RDK", [model_dict])]
+    b_val, =     yield [("RV", [b])]
+    model_dict,= yield [("RD", [a, "model"])]
+    metamodel, = yield [("RD", [a, "metamodel"])]
+    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]
 
@@ -140,14 +133,14 @@ 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", [metamodel, "inheritance"])]
 
     # Now we figure out which types are valid for the specified model
     desired_types = set()
-    mm_element =    yield [("RD", [mm_dict, b_val])]
+    mm_element, =    yield [("RD", [mm_dict, b_val])]
     work_list = []
     work_list.append(mm_element)
-    mm_typing =     yield [("RD", [metamodel, "type_mapping"])]
+    mm_typing, =     yield [("RD", [metamodel, "type_mapping"])]
 
     while work_list:
         mm_element = work_list.pop()
@@ -159,11 +152,11 @@ def allInstances(a, b, **remainder):
         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])]
+        incoming, =  yield [("RI", [mm_element])]
         for i in incoming:
-            t =     yield [("RDN", [mm_typing, i])]
+            t, =     yield [("RDN", [mm_typing, i])]
             if t == inheritance_type:
-                e = yield [("RE", [i])]
+                e, = yield [("RE", [i])]
                 # Add the source of the inheritance link to the work list
                 work_list.append(e[0])
 
@@ -174,7 +167,7 @@ def allInstances(a, b, **remainder):
         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", [])]
+    result, =    yield [("CN", [])]
     v =         yield [("RV", [i]) for i in final]
     _ =    yield [("CE", [result, i]) for i in final]
     raise PrimitiveFinished(result)
@@ -184,15 +177,15 @@ def add_AL(a, b, **remainder):
     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])]
+    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])]
+    result, = yield [("CNV", ["__%s" % b])]
 
     # All the action language elements and their expected output links
     type_links = {
@@ -227,7 +220,7 @@ def add_AL(a, b, **remainder):
 
         # Determine type of element
         if expected_type == "":
-            value = yield [("RV", [worknode])]
+            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"]:
@@ -239,14 +232,14 @@ def add_AL(a, b, **remainder):
 
         # Fill the cache
         if expected_type not in type_cache:
-            type_cache[expected_type] = yield [("RD", [metamodel_dict, expected_type])]
+            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])]
+        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")
 
@@ -256,13 +249,13 @@ def add_AL(a, b, **remainder):
             link_name, destination_type = link
 
             # Check if the link actually exists
-            destination = yield [("RD", [worknode, link_name])]
+            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, = yield [("RDE", [worknode, link_name])]
+                edge_outlinks, = yield [("RO", [edge])]
                 edge_outlink = edge_outlinks[0]
-                edge_name = yield [("RE", [edge_outlink])]
+                edge_name, = yield [("RE", [edge_outlink])]
                 edge_name = edge_name[1]
                 # Now add: edge, edge_outlink, edge_name
 
@@ -271,20 +264,20 @@ def add_AL(a, b, **remainder):
                 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]])]
+                    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"]])]
+                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"]])]
+                    t, = yield [("CE", [type_map, type_cache["String"]])]
                     yield [("CE", [t, edge_name])]
                     added.add(edge_name)
 
@@ -294,48 +287,44 @@ def add_AL(a, b, **remainder):
     raise PrimitiveFinished(result)
 
 def get_superclasses(a, b, **remainder):
-    inheritance =   yield [("RD", [a, "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])]
+    inheritance, =   yield [("RD", [a, "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", [])]
+    result, =        yield [("CN", [])]
     worklist = [subclass]
     while worklist:
         subclass = worklist.pop()
         res = elem_to_name[subclass]
         yield [("CE", [result, res])]
 
-        outgoing =      yield [("RO", [subclass])]
+        outgoing, =      yield [("RO", [subclass])]
         types =         yield [("RDN", [type_mapping, i]) for i in outgoing]
-        types = [types] if len(outgoing) == 1 else types
 
         for i, t in enumerate(types):
             if t == inheritance:
                 # Found an inheritance link!
                 elem = outgoing[i]
-                src, dst = \
-                        yield [("RE", [elem])]
+                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 = \
+    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]
-    limit_set_names = [limit_set_names] if len(limit_set) == 1 else limit_set_names
+    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]
-    limit_set = [limit_set] if len(limit_set_names) == 1 else limit_set
 
     try:
         gen = get_superclasses(a, b)
@@ -344,74 +333,88 @@ def selectPossibleIncoming(a, b, c, **remainder):
             inp =   yield gen.send(inp)
     except PrimitiveFinished as e:
         superclasses = e.result
-        vals = yield [("RO", [superclasses])]
+        vals, = yield [("RO", [superclasses])]
         superclasses = yield [("RE", [i]) for i in vals]
-        superclasses = [superclasses] if len(vals) == 1 else superclasses
         superclasses = [i[1] for i in superclasses]
 
     superclass_names = yield [("RV", [i]) for i in superclasses]
-    superclass_names = [superclass_names] if len(superclasses) == 1 else superclass_names
     elems =         yield [("RD", [model_dict, i]) for i in superclass_names]
-    elems = [elems] if len(superclasses) == 1 else elems
 
-    result =        yield [("CN", [])]
+    result, =        yield [("CN", [])]
     for i, edge in enumerate(limit_set):
-        src, dst =  yield [("RE", [edge])]
+        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 = \
+    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]
-    limit_set_names = [limit_set_names] if len(limit_set) == 1 else limit_set_names
     name_values =   yield [("RV", [i]) for i in limit_set_names]
     limit_set =     yield [("RD", [model_dict, i]) for i in name_values]
-    limit_set = [limit_set] if len(limit_set_names) == 1 else limit_set
 
     try:
         gen = get_superclasses(a, b)
         inp = None
         while 1:
-            inp =   yield gen.send(inp)
+            inp =  yield gen.send(inp)
     except PrimitiveFinished as e:
         superclasses = e.result
-        vals = yield [("RO", [superclasses])]
+        vals, = yield [("RO", [superclasses])]
         superclasses = yield [("RE", [i]) for i in vals]
-        superclasses = [superclasses] if len(vals) == 1 else superclasses
         superclasses = [i[1] for i in superclasses]
 
     superclass_names = yield [("RV", [i]) for i in superclasses]
-    superclass_names = [superclass_names] if len(superclasses) == 1 else superclass_names
     elems =         yield [("RD", [model_dict, i]) for i in superclass_names]
-    elems = [elems] if len(superclasses) == 1 else elems
 
-    result =        yield [("CN", [])]
+    result, =        yield [("CN", [])]
     for i, edge in enumerate(limit_set):
-        src, dst =  yield [("RE", [edge])]
+        srcdst, =  yield [("RE", [edge])]
+        src, dst = srcdst
         if src in elems:
             yield [("CE", [result, limit_set_names[i]])]
 
     raise PrimitiveFinished(result)
 
-def read_symbols(a, b, **remainder):
-    b_v =       yield [("RV", [b])]
-    obj =       yield [("RD", [a, b_v])]
-    node =      yield [("RD", [obj, "symbols"])]
-    keys =      yield [("RDK", [node])]
-    keys_v =    yield [("RV", [i]) for i in keys]
-    keys_v = [keys_v] if not isinstance(keys_v, list) else keys_v
-    is_in =     yield [("RD", [node, i]) for i in keys_v]
-    is_in = [is_in] if not isinstance(is_in, list) else is_in
-    is_in_v =   yield [("RV", [i]) for i in is_in]
-    is_in_v = [is_in_v] if not isinstance(is_in_v, list) else is_in_v
-
-    result_v = ["%s:%s\n" % (key, "1" if value else "0") for key, value in zip(keys_v, is_in_v)]
-    result_v = "".join(result_v)
-    result =    yield [("CNV", [result_v])]
+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)

+ 105 - 114
kernel/modelverse_kernel/main.py

@@ -42,8 +42,8 @@ class ModelverseKernel(object):
             raise
 
     def execute_rule(self, username):
-        user_root =     yield [("RD", [self.root, username])]
-        user_frame =    yield [("RD", [user_root, "frame"])]
+        user_root, =    yield [("RD", [self.root, username])]
+        user_frame, =   yield [("RD", [user_root, "frame"])]
         inst, phase =   yield [("RD", [user_frame, "IP"]),
                                ("RD", [user_frame, "phase"]),
                               ]
@@ -53,18 +53,20 @@ class ModelverseKernel(object):
                                ("RV", [inst]),
                               ]
         if self.new_debug is not None:
-            self.debug_info = yield [("RV", [self.new_debug])]
+            self.debug_info, = yield [("RV", [self.new_debug])]
 
         if phase_v == "finish":
             gen = self.helper_init(user_root)
+        elif inst is None:
+            raise Exception("Instruction pointer could not be found!")
         elif isinstance(phase_v, string_types):
             if phase_v == "init" and inst in self.compiled:
                 #print("%-30s(%s)" % ("COMPILED " + str(self.primitives[inst]), phase_v))
-                gen = self.execute_primitive(user_root, inst)
+                gen = self.execute_primitive(user_root, inst, username)
             elif inst_v is None:
                 raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
             else:
-                #print("%-30s(%s)" % (inst_v["value"], phase_v))
+                #print("%-30s(%s) -- %s" % (inst_v["value"], phase_v, username))
                 gen = getattr(self, "%s_%s" % (inst_v["value"], phase_v))(user_root)
         elif inst_v is None:
             raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
@@ -77,7 +79,6 @@ class ModelverseKernel(object):
         try:
             inp = None
             while 1:
-                # Without checking:
                 inp = yield gen.send(inp)
         except StopIteration:
             pass
@@ -86,41 +87,32 @@ class ModelverseKernel(object):
     ### Process primitives ###
     ##########################
     def load_primitives(self, username):
-        hierarchy =     yield [("RD", [self.root, "__hierarchy"])]
-        primitives =    yield [("RD", [hierarchy, "primitives"])]
-        keys =          yield [("RDK", [primitives])]
-        function_names =yield [("RV", [f]) for f in keys]
-        signatures =    yield [("RDN", [primitives, f]) for f in keys]
-        bodies =        yield [("RD", [f, "body"]) for f in signatures]
+        hierarchy, =     yield [("RD", [self.root, "__hierarchy"])]
+        primitives, =    yield [("RD", [hierarchy, "primitives"])]
+        keys, =          yield [("RDK", [primitives])]
+        function_names = yield [("RV", [f]) for f in keys]
+        signatures  =    yield [("RDN", [primitives, f]) for f in keys]
+        bodies =         yield [("RD", [f, "body"]) for f in signatures]
         for i in range(len(keys)):
             self.primitives[bodies[i]] = getattr(primitive_functions, function_names[i])
         self.compiled.update(self.primitives)
 
-    def execute_primitive(self, user_root, inst):
+    def execute_primitive(self, user_root, inst, username):
         # execute_primitive
-        user_frame =    yield [("RD", [user_root, "frame"])]
-        symbols =       yield [("RD", [user_frame, "symbols"])]
-        all_links =     yield [("RO", [symbols])]
-        if len(all_links) == 1:
-            # Single parameter, so avoid all list comprehensions
-            all_links = all_links[0]
-            containers =    yield [("RE", [all_links])]
-            outgoings =     yield [("RO", [all_links])]
-            dict_values =   yield [("RD", [containers[1], "value"])]
-            formals_1 =     yield [("RE", [outgoings[0]])]
-            dict_keys_ref = yield [("RD", [formals_1[1], "name"])]
-            dict_keys =     yield [("RV", [dict_keys_ref])]
-            parameters = {dict_keys: dict_values}
-        else:
-            containers =    yield [("RE", [v]) for v in all_links]
-            outgoings =     yield [("RO", [v]) for v in all_links]
-            dict_values =   yield [("RD", [v[1], "value"]) for v in containers]
-            formals_1 =     yield [("RE", [v[0]]) for v in outgoings]
-            dict_keys_ref = yield [("RD", [v[1], "name"]) for v in formals_1]
-            dict_keys =     yield [("RV", [v]) for v in dict_keys_ref]
-            parameters = dict(zip(dict_keys, dict_values))
+        user_frame, =    yield [("RD", [user_root, "frame"])]
+        symbols, =       yield [("RD", [user_frame, "symbols"])]
+        all_links, =     yield [("RO", [symbols])]
+        containers =    yield [("RE", [v]) for v in all_links]
+        outgoings =     yield [("RO", [v]) for v in all_links]
+        dict_values =   yield [("RD", [v[1], "value"]) for v in containers]
+        formals_1 =     yield [("RE", [v[0]]) for v in outgoings]
+        dict_keys_ref = yield [("RD", [v[1], "name"]) for v in formals_1]
+        dict_keys =     yield [("RV", [v]) for v in dict_keys_ref]
+        parameters = dict(zip(dict_keys, dict_values))
 
         parameters["root"] = self.root
+        parameters["user_root"] = user_root
+        parameters["username"] = username
 
         # prim is a generator itself!
         try:
@@ -141,8 +133,8 @@ class ModelverseKernel(object):
             #    raise Exception("Primitive raised exception: value of None for operation %s with parameters %s" % (self.compiled[inst], str(parameters)))
 
         # Clean up the current stack, as if a return happened
-        old_frame =     yield [("RD", [user_frame, "prev"])]
-        lnk =           yield [("RDE", [old_frame, "returnvalue"])]
+        old_frame, =    yield [("RD", [user_frame, "prev"])]
+        lnk, =          yield [("RDE", [old_frame, "returnvalue"])]
         _, _, _, _ =    yield [("CD", [old_frame, "returnvalue", result]),
                                ("CD", [user_root, "frame", old_frame]),
                                ("DE", [lnk]),
@@ -153,8 +145,8 @@ class ModelverseKernel(object):
     ### Execute input and output methods ###
     ########################################
     def get_output(self, username):
-        user_root =         yield [("RD", [self.root, username])]
-        first_output =      yield [("RD", [user_root, "output"])]
+        user_root, =        yield [("RD", [self.root, username])]
+        first_output, =     yield [("RD", [user_root, "output"])]
         next_output, rv =   yield [("RD", [first_output, "next"]),
                                    ("RD", [first_output, "value"]),
                                   ]
@@ -162,18 +154,18 @@ class ModelverseKernel(object):
             self.success = False
             self.returnvalue = {"id": None, "value": ""}
         else:
-            rv_value =      yield [("RV", [rv])]
+            rv_value, =     yield [("RV", [rv])]
             _, _ =          yield [("CD", [user_root, "output", next_output]),
                                    ("DN", [first_output]),
                                   ]
             self.returnvalue = {"id": rv, "value": rv_value}
 
     def set_input(self, username, element_type, value):
-        user_root =         yield [("RD", [self.root, username])]
+        user_root, =        yield [("RD", [self.root, username])]
         old_input, link =   yield [("RD", [user_root, "last_input"]),
                                    ("RDE", [user_root, "last_input"]),
                                   ]
-        new_input =         yield [("CN", [])]
+        new_input, =        yield [("CN", [])]
         _, _ =              yield [("CD", [user_root, "last_input", new_input]),
                                    ("CD", [old_input, "next", new_input]),
                                   ]
@@ -181,7 +173,7 @@ class ModelverseKernel(object):
         if element_type == "R":
             new_value = int(value)
         elif element_type == "V":
-            new_value =     yield [("CNV", [value])]
+            new_value, =    yield [("CNV", [value])]
         _, _ =              yield [("CD", [old_input, "value", new_value]),
                                    ("DE", [link])
                                   ]
@@ -191,12 +183,12 @@ class ModelverseKernel(object):
     ### Transformation rules for instructions ###
     #############################################
     def break_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         phase_link, ip_link = \
                             yield [("RDE", [user_frame, "phase"]),
                                    ("RDE", [user_frame, "IP"])
                                   ]
-        inst =              yield [("RD", [user_frame, "IP"])]
+        inst, =             yield [("RD", [user_frame, "IP"])]
         while_inst, new_phase = \
                             yield [("RD", [inst, "while"]),
                                    ("CNV", ["finish"]),
@@ -208,17 +200,17 @@ class ModelverseKernel(object):
                                   ]
 
     def continue_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         ip_link, inst =     yield [("RDE", [user_frame, "IP"]),
                                    ("RD", [user_frame, "IP"]),
                                   ]
-        while_inst =        yield [("RD", [inst, "while"])]
+        while_inst, =       yield [("RD", [inst, "while"])]
         _, _ =              yield [("CD", [user_frame, "IP", while_inst]),
                                    ("DE", [ip_link]),
                                   ]
 
     def if_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         evalstack, evalstack_link = \
                             yield [("RD", [user_frame, "evalstack"]),
                                    ("RDE", [user_frame, "evalstack"]),
@@ -226,7 +218,7 @@ class ModelverseKernel(object):
         inst, ip_link =     yield [("RD", [user_frame, "IP"]),
                                    ("RDE", [user_frame, "IP"]),
                                   ]
-        cond =              yield [("RD", [inst, "cond"])]
+        cond, =             yield [("RD", [inst, "cond"])]
         new_evalstack, new_phase = \
                             yield [("CN", []),
                                    ("CNV", ["cond"]),
@@ -242,12 +234,12 @@ class ModelverseKernel(object):
                                   ]
 
     def if_cond(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         returnvalue, inst = yield [("RD", [user_frame, "returnvalue"]),
                                    ("RD", [user_frame, "IP"]),
                                   ]
-        returnvalue_v =     yield [("RV", [returnvalue])]
-        _else =             yield [("RD", [inst, "else"])]
+        returnvalue_v, =    yield [("RV", [returnvalue])]
+        _else, =            yield [("RD", [inst, "else"])]
 
         if returnvalue_v:
             phase_link, evalstack, evalstack_link, ip_link, _then, new_evalstack, evalstack_phase, new_phase = \
@@ -304,7 +296,7 @@ class ModelverseKernel(object):
                                   ]
 
     def while_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         evalstack, evalstack_link, ip_link, inst = \
                             yield [("RD", [user_frame, "evalstack"]),
                                    ("RDE", [user_frame, "evalstack"]),
@@ -327,9 +319,9 @@ class ModelverseKernel(object):
                                   ]
 
     def while_cond(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
-        returnvalue =       yield [("RD", [user_frame, "returnvalue"])]
-        returnvalue_v =     yield [("RV", [returnvalue])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
+        returnvalue, =      yield [("RD", [user_frame, "returnvalue"])]
+        returnvalue_v, =    yield [("RV", [returnvalue])]
 
         if returnvalue_v:
             phase_link, evalstack, evalstack_link, ip_link, inst = \
@@ -339,7 +331,7 @@ class ModelverseKernel(object):
                                    ("RDE", [user_frame, "IP"]),
                                    ("RD", [user_frame, "IP"]),
                                   ]
-            body =          yield [("RD", [inst, "body"])]
+            body, =         yield [("RD", [inst, "body"])]
             new_evalstack, new_phase, evalstack_phase = \
                             yield [("CN", []),
                                    ("CNV", ["init"]),
@@ -366,7 +358,7 @@ class ModelverseKernel(object):
                                   ]
 
     def access_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         evalstack, evalstack_link, inst, ip_link = \
                             yield [("RD", [user_frame, "evalstack"]),
                                    ("RDE", [user_frame, "evalstack"]),
@@ -389,7 +381,7 @@ class ModelverseKernel(object):
                                   ]
 
     def access_eval(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         phase_link, returnvalue_link, returnvalue = \
                             yield [("RDE", [user_frame, "phase"]),
                                    ("RDE", [user_frame, "returnvalue"]),
@@ -405,7 +397,7 @@ class ModelverseKernel(object):
                                   ]
 
     def resolve_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         symbols, evalstack, evalstack_link, ip_link, inst = \
                             yield [("RD", [user_frame, "symbols"]),
                                    ("RD", [user_frame, "evalstack"]),
@@ -413,8 +405,8 @@ class ModelverseKernel(object):
                                    ("RDE", [user_frame, "IP"]),
                                    ("RD", [user_frame, "IP"]),
                                   ]
-        var =               yield [("RD", [inst, "var"])]
-        variable =          yield [("RDN", [symbols, var])]
+        var, =              yield [("RD", [inst, "var"])]
+        variable, =         yield [("RDN", [symbols, var])]
 
         if variable is None:
             phase_link, returnvalue_link, _globals, var_name = \
@@ -439,8 +431,8 @@ class ModelverseKernel(object):
                     # We have a compiled function ready!
                     # Now we have to bind the ID to the compiled functions
                     # For this, we read out the body of the resolved data
-                    compiler_val = yield [("RD", [variable, "value"])]
-                    compiler_body = yield [("RD", [compiler_val, "body"])]
+                    compiler_val, =  yield [("RD", [variable, "value"])]
+                    compiler_body, = yield [("RD", [compiler_val, "body"])]
                     self.compiled[compiler_body] = compiled_function
 
         else:
@@ -449,7 +441,7 @@ class ModelverseKernel(object):
                                    ("RDE", [user_frame, "returnvalue"]),
                                    ("CNV", ["finish"]),
                                   ]
-
+        print("Resolved to " + str(variable))
         _, _, _, _ =        yield [("CD", [user_frame, "phase", new_phase]),
                                    ("CD", [user_frame, "returnvalue", variable]),
                                    ("DE", [phase_link]),
@@ -457,7 +449,7 @@ class ModelverseKernel(object):
                                   ]
 
     def assign_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         evalstack, evalstack_link, ip_link, inst = \
                             yield [("RD", [user_frame, "evalstack"]),
                                    ("RDE", [user_frame, "evalstack"]),
@@ -480,7 +472,7 @@ class ModelverseKernel(object):
                                   ]
 
     def assign_value(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         phase_link, evalstack, returnvalue, evalstack_link, ip_link, inst = \
                             yield [("RDE", [user_frame, "phase"]),
                                    ("RD", [user_frame, "evalstack"]),
@@ -510,7 +502,7 @@ class ModelverseKernel(object):
                                   ]
 
     def assign_assign(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         phase_link, returnvalue, variable_link, variable = \
                             yield [("RDE", [user_frame, "phase"]),
                                    ("RD", [user_frame, "returnvalue"]),
@@ -529,12 +521,12 @@ class ModelverseKernel(object):
                                   ]
                     
     def return_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
-        inst =              yield [("RD", [user_frame, "IP"])]
-        value =             yield [("RD", [inst, "value"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
+        inst, =             yield [("RD", [user_frame, "IP"])]
+        value, =            yield [("RD", [inst, "value"])]
 
         if value is None:
-            prev_frame =    yield [("RD", [user_frame, "prev"])]
+            prev_frame, =   yield [("RD", [user_frame, "prev"])]
             _, _ =          yield [("CD", [user_root, "frame", prev_frame]),
                                    ("DN", [user_frame]),
                                   ]
@@ -557,8 +549,8 @@ class ModelverseKernel(object):
                                   ]
 
     def return_eval(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
-        prev_frame =        yield [("RD", [user_frame, "prev"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
+        prev_frame, =       yield [("RD", [user_frame, "prev"])]
         returnvalue, old_returnvalue_link = \
                             yield [("RD", [user_frame, "returnvalue"]),
                                    ("RDE", [prev_frame, "returnvalue"]),
@@ -570,7 +562,7 @@ class ModelverseKernel(object):
                                   ]
 
     def constant_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         phase_link, returnvalue_link, inst = \
                             yield [("RDE", [user_frame, "phase"]),
                                    ("RDE", [user_frame, "returnvalue"]),
@@ -586,9 +578,9 @@ class ModelverseKernel(object):
                                   ]
 
     def helper_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
-        inst =              yield [("RD", [user_frame, "IP"])]
-        next =              yield [("RD", [inst, "next"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
+        inst, =             yield [("RD", [user_frame, "IP"])]
+        next, =             yield [("RD", [inst, "next"])]
 
         if next is None:
             ip_link, phase_link, evalstack_top = \
@@ -596,7 +588,7 @@ class ModelverseKernel(object):
                                    ("RDE", [user_frame, "phase"]),
                                    ("RD", [user_frame, "evalstack"]),
                                   ]
-            evalstack =     yield [("RD", [evalstack_top, "prev"])]
+            evalstack, =    yield [("RD", [evalstack_top, "prev"])]
             evalstack_inst, evalstack_phase, evalstack_inst_link, evalstack_phase_link = \
                             yield [("RD", [evalstack, "inst"]),
                                    ("RD", [evalstack, "phase"]),
@@ -626,7 +618,7 @@ class ModelverseKernel(object):
                                   ]
 
     def call_init(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         symbols, evalstack, evalstack_link, ip_link, inst = \
                             yield [("RD", [user_frame, "symbols"]),
                                    ("RD", [user_frame, "evalstack"]),
@@ -653,7 +645,7 @@ class ModelverseKernel(object):
                                    ("DE", [ip_link]),
                                   ]
         else:
-            new_evalstack = yield [("CN", [])]
+            new_evalstack,= yield [("CN", [])]
             _, _, _, _, _, _, _ = \
                             yield [("CD", [user_frame, "evalstack", new_evalstack]),
                                    ("CD", [new_evalstack, "prev", evalstack]),
@@ -665,12 +657,12 @@ class ModelverseKernel(object):
                                   ]
 
     def call_call(self, user_root):
-        user_frame =        yield [("RD", [user_root, "frame"])]
-        inst =              yield [("RD", [user_frame, "IP"])]
-        param =             yield [("RD", [inst, "last_param"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
+        inst, =             yield [("RD", [user_frame, "IP"])]
+        param, =            yield [("RD", [inst, "last_param"])]
 
         if param is None:
-            returnvalue =   yield [("RD", [user_frame, "returnvalue"])]
+            returnvalue, =  yield [("RD", [user_frame, "returnvalue"])]
             body, phase_link, frame_link, prev_phase, new_phase, new_frame, new_evalstack, new_symbols, new_returnvalue = \
                             yield [("RD", [returnvalue, "body"]),
                                    ("RDE", [user_frame, "phase"]),
@@ -707,14 +699,14 @@ class ModelverseKernel(object):
                                    ("RD", [new_frame, "symbols"]),
                                    ("RD", [new_frame, "IP"]),
                                   ]
-            signature =     yield [("RRD", [new_IP, "body"])]
+            signature, =    yield [("RRD", [new_IP, "body"])]
             signature = signature[0]
             sig_params, last_param = \
                             yield [("RD", [signature, "params"]),
                                    ("RD", [inst, "last_param"]),
                                   ]
-            name =          yield [("RD", [last_param, "name"])]
-            name_value =    yield [("RV", [name])]
+            name, =         yield [("RD", [last_param, "name"])]
+            name_value, =   yield [("RV", [name])]
             returnvalue, formal_parameter, new_phase, variable = \
                             yield [("RD", [user_frame, "returnvalue"]),
                                    ("RD", [sig_params, name_value]),
@@ -743,8 +735,7 @@ class ModelverseKernel(object):
             raise Exception("%s: error: could not find any overlap" % self.debug_info)
 
     def call_param(self, user_root):
-        #TODO this code is likely very buggy!
-        user_frame =        yield [("RD", [user_root, "frame"])]
+        user_frame, =       yield [("RD", [user_root, "frame"])]
         inst, phase =       yield [("RD", [user_frame, "IP"]),
                                    ("RD", [user_frame, "phase"]),
                                   ]
@@ -752,7 +743,7 @@ class ModelverseKernel(object):
                             yield [("RD", [inst, "params"]),
                                    ("RD", [inst, "last_param"]),
                                   ]
-        next_param =        yield [("RD", [params, "next_param"])]
+        next_param, =       yield [("RD", [params, "next_param"])]
 
         if params == phase:
             phase_link, ip_link, returnvalue, param_value, evalstack, evalstack_link = \
@@ -763,7 +754,7 @@ class ModelverseKernel(object):
                                    ("RD", [user_frame, "evalstack"]),
                                    ("RDE", [user_frame, "evalstack"]),
                                   ]
-            body =          yield [("RD", [returnvalue, "body"])]
+            body, =         yield [("RD", [returnvalue, "body"])]
             new_frame, prev_evalstack, new_phase, prev_phase, new_evalstack, new_symbols, new_returnvalue = \
                             yield [("CN", []),
                                    ("CN", []),
@@ -793,7 +784,7 @@ class ModelverseKernel(object):
             if next_param is not None:
                 _ =         yield [("CD", [evalstack, "phase", next_param])]
             else:
-                evalstack_phase = \
+                evalstack_phase, = \
                             yield [("CNV", ["call"])]
                 _ =         yield [("CD", [evalstack, "phase", evalstack_phase])]
         else:
@@ -811,18 +802,18 @@ class ModelverseKernel(object):
                                    ("RD", [new_frame, "symbols"]),
                                    ("RD", [new_frame, "IP"]),
                                   ]
-            signature =     yield [("RRD", [new_IP, "body"])]
+            signature, =    yield [("RRD", [new_IP, "body"])]
             signature = signature[0]
-            sig_params =    yield [("RD", [signature, "params"])]
+            sig_params, =   yield [("RD", [signature, "params"])]
 
             if last_param == phase:
-                prev_param = \
+                prev_param, = \
                             yield [("RRD", [last_param, "next_param"])]
                 prev_param = prev_param[0]
-                name =      yield [("RD", [prev_param, "name"])]
-                name_value = \
+                name, =     yield [("RD", [prev_param, "name"])]
+                name_value, = \
                             yield [("RV", [name])]
-                evalstack_phase = \
+                evalstack_phase, = \
                             yield [("CNV", ["call"])]
                 _ =         yield [("CD", [evalstack, "phase", evalstack_phase])]
                 formal_parameter, param_value = \
@@ -830,7 +821,7 @@ class ModelverseKernel(object):
                                    ("RD", [last_param, "value"]),
                                   ]
             else:
-                param_b =   yield [("RD", [user_frame, "phase"])]
+                param_b, =  yield [("RD", [user_frame, "phase"])]
                 param_c, param_a = \
                             yield [("RD", [param_b, "next_param"]),
                                    ("RRD", [param_b, "next_param"]),
@@ -840,7 +831,7 @@ class ModelverseKernel(object):
                             yield [("RD", [param_a, "name"]),
                                    ("RD", [param_b, "value"]),
                                   ]
-                name_value = \
+                name_value, = \
                             yield [("RV", [name])]
                 formal_parameter, _ = \
                             yield [("RD", [sig_params, name_value]),
@@ -862,7 +853,7 @@ class ModelverseKernel(object):
                                ("CD", [variable, "value", returnvalue]),
                               ]
 
-            t1 =        yield [("CE", [new_symbols, variable])]
+            t1, =       yield [("CE", [new_symbols, variable])]
             _, _, _, _ = \
                         yield [("CE", [t1, formal_parameter]),
                                ("DE", [phase_link]),
@@ -871,7 +862,7 @@ class ModelverseKernel(object):
                               ]
 
     def input_init(self, user_root):
-        user_frame =    yield [("RD", [user_root, "frame"])]
+        user_frame, =   yield [("RD", [user_root, "frame"])]
         returnvalue_link, _input = \
                         yield [("RDE", [user_frame, "returnvalue"]),
                                ("RD", [user_root, "input"]),
@@ -899,7 +890,7 @@ class ModelverseKernel(object):
             self.success = False
 
     def output_init(self, user_root):
-        user_frame =    yield [("RD", [user_root, "frame"])]
+        user_frame, =   yield [("RD", [user_root, "frame"])]
         evalstack, evalstack_link, ip_link, inst = \
                         yield [("RD", [user_frame, "evalstack"]),
                                ("RDE", [user_frame, "evalstack"]),
@@ -922,7 +913,7 @@ class ModelverseKernel(object):
                               ]
 
     def output_output(self, user_root):
-        user_frame =    yield [("RD", [user_root, "frame"])]
+        user_frame, =   yield [("RD", [user_root, "frame"])]
         returnvalue_link, returnvalue, last_output, phase_link, last_output_link, new_last_output, finish = \
                         yield [("RDE", [user_frame, "returnvalue"]),
                                ("RD", [user_frame, "returnvalue"]),
@@ -942,8 +933,8 @@ class ModelverseKernel(object):
                               ]
 
     def declare_init(self, user_root):
-        user_frame =    yield [("RD", [user_root, "frame"])]
-        inst =          yield [("RD", [user_frame, "IP"])]
+        user_frame, =   yield [("RD", [user_root, "frame"])]
+        inst, =         yield [("RD", [user_frame, "IP"])]
         new_var, symbols, phase_link, empty_node, new_phase = \
                         yield [("RD", [inst, "var"]),
                                ("RD", [user_frame, "symbols"]),
@@ -952,18 +943,18 @@ class ModelverseKernel(object):
                                ("CNV", ["finish"]),
                               ]
 
-        exists = yield [("RDN", [symbols, new_var])]
+        exists, =       yield [("RDN", [symbols, new_var])]
         if exists is None:
-            new_edge =      yield [("CE", [symbols, empty_node])]
-            _ =             yield [("CE", [new_edge, new_var])]
+            new_edge, = yield [("CE", [symbols, empty_node])]
+            _ =         yield [("CE", [new_edge, new_var])]
 
-        _, _ =       yield [   ("CD", [user_frame, "phase", new_phase]),
+        _, _ =          yield [("CD", [user_frame, "phase", new_phase]),
                                ("DE", [phase_link]),
                               ]
 
     def global_init(self, user_root):
-        user_frame =    yield [("RD", [user_root, "frame"])]
-        inst =          yield [("RD", [user_frame, "IP"])]
+        user_frame, =   yield [("RD", [user_root, "frame"])]
+        inst, =         yield [("RD", [user_frame, "IP"])]
         new_var, global_symbols, phase_link, empty_node, new_phase = \
                         yield [("RD", [inst, "var"]),
                                ("RD", [user_root, "globals"]),
@@ -972,8 +963,8 @@ class ModelverseKernel(object):
                                ("CNV", ["finish"]),
                               ]
 
-        value = yield [("RV", [new_var])]
-        exists = yield [("RD", [global_symbols, value])]
+        value, =        yield [("RV", [new_var])]
+        exists, =       yield [("RD", [global_symbols, value])]
 
         if exists is None:
             yield [("CD", [global_symbols, value, empty_node])]

+ 131 - 140
kernel/modelverse_kernel/primitives.py

@@ -5,92 +5,92 @@ class PrimitiveFinished(Exception):
     
 def integer_subtraction(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value - b_value])]
+    result, = yield [("CNV", [a_value - b_value])]
     raise PrimitiveFinished(result)
 
 def integer_addition(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value + b_value])]
+    result, = yield [("CNV", [a_value + b_value])]
     raise PrimitiveFinished(result)
 
 def integer_multiplication(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value * b_value])]
+    result, = yield [("CNV", [a_value * b_value])]
     raise PrimitiveFinished(result)
 
 def integer_division(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [int(a_value) / b_value])]
+    result, = yield [("CNV", [int(a_value) / b_value])]
     raise PrimitiveFinished(result)
 
 def integer_gt(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value > b_value])]
+    result, = yield [("CNV", [a_value > b_value])]
     raise PrimitiveFinished(result)
 
 def integer_lt(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value < b_value])]
+    result, = yield [("CNV", [a_value < b_value])]
     raise PrimitiveFinished(result)
 
 def integer_neg(a, **remainder):
-    a_value =           yield [("RV", [a])]
-    result = yield [("CNV", [-a_value])]
+    a_value, =          yield [("RV", [a])]
+    result, = yield [("CNV", [-a_value])]
     raise PrimitiveFinished(result)
 
 def bool_and(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value and b_value])]
+    result, = yield [("CNV", [a_value and b_value])]
     raise PrimitiveFinished(result)
 
 def bool_or(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value or b_value])]
+    result, = yield [("CNV", [a_value or b_value])]
     raise PrimitiveFinished(result)
 
 def bool_not(a, **remainder):
-    a_value =           yield [("RV", [a])]
-    result = yield [("CNV", [not a_value])]
+    a_value, =          yield [("RV", [a])]
+    result, = yield [("CNV", [not a_value])]
     raise PrimitiveFinished(result)
 
 def float_subtraction(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value - b_value])]
+    result, = yield [("CNV", [a_value - b_value])]
     raise PrimitiveFinished(result)
 
 def float_addition(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value + b_value])]
+    result, = yield [("CNV", [a_value + b_value])]
     raise PrimitiveFinished(result)
 
 def float_multiplication(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value * b_value])]
+    result, = yield [("CNV", [a_value * b_value])]
     raise PrimitiveFinished(result)
 
 def float_division(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value / b_value])]
+    result, = yield [("CNV", [a_value / b_value])]
     raise PrimitiveFinished(result)
 
 def float_gt(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value > b_value])]
+    result, = yield [("CNV", [a_value > b_value])]
     raise PrimitiveFinished(result)
 
 def float_lt(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value < b_value])]
+    result, = yield [("CNV", [a_value < b_value])]
     raise PrimitiveFinished(result)
 
 def float_neg(a, **remainder):
-    a_value =           yield [("RV", [a])]
-    result = yield [("CNV", [-a_value])]
+    a_value, =          yield [("RV", [a])]
+    result, = yield [("CNV", [-a_value])]
     raise PrimitiveFinished(result)
 
 def string_join(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [str(a_value) + str(b_value)])]
+    result, = yield [("CNV", [str(a_value) + str(b_value)])]
     raise PrimitiveFinished(result)
 
 def string_split(a, b, **remainder):
@@ -103,119 +103,119 @@ def string_split(a, b, **remainder):
 
 def string_get(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value[b_value]])]
+    result, = yield [("CNV", [a_value[b_value]])]
     raise PrimitiveFinished(result)
 
 def string_len(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [len(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [len(a_value)])]
     raise PrimitiveFinished(result)
 
 def value_eq(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value == b_value])]
+    result, = yield [("CNV", [a_value == b_value])]
     raise PrimitiveFinished(result)
 
 def value_neq(a, b, **remainder):
     a_value, b_value =  yield [("RV", [a]), ("RV", [b])]
-    result = yield [("CNV", [a_value != b_value])]
+    result, = yield [("CNV", [a_value != b_value])]
     raise PrimitiveFinished(result)
 
 def element_eq(a, b, **remainder):
-    result = yield [("CNV", [a == b])]
+    result, = yield [("CNV", [a == b])]
     raise PrimitiveFinished(result)
 
 def element_neq(a, b, **remainder):
-    result = yield [("CNV", [a != b])]
+    result, = yield [("CNV", [a != b])]
     raise PrimitiveFinished(result)
 
 def cast_a2s(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [str(a_value["value"])])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [str(a_value["value"])])]
     raise PrimitiveFinished(result)
 
 def cast_i2f(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [float(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [float(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_i2s(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [str(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [str(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_i2b(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [bool(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [bool(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_f2i(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [int(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [int(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_f2s(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [str(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [str(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_f2b(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [bool(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [bool(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_s2i(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [int(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [int(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_s2f(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [float(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [float(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_s2b(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [bool(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [bool(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_b2i(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [int(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [int(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_b2f(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [float(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [float(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_b2s(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [str(a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [str(a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_e2s(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", ["{ID: %s, value: %s}" % (a, a_value)])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", ["{ID: %s, value: %s}" % (a, a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_v2s(a, **remainder):
-    a_value = yield [("RV", [a])]
+    a_value, = yield [("RV", [a])]
     if isinstance(a_value, (str, unicode)):
         # String should be encoded to distinguish between 3 and "3"
         a_value = '"%s"' % a_value
     elif isinstance(a_value, dict):
         # Action or type
         a_value = a_value["value"]
-    result = yield [("CNV", ["%s" % (a_value)])]
+    result, = yield [("CNV", ["%s" % (a_value)])]
     raise PrimitiveFinished(result)
 
 def cast_id2s(a, **remainder):
-    result = yield [("CNV", ["%s" % (a)])]
+    result, = yield [("CNV", ["%s" % (a)])]
     raise PrimitiveFinished(result)
 
 def list_append(a, b, **remainder):
-    a_outgoing = yield [("RO", [a])]
+    a_outgoing, = yield [("RO", [a])]
     _ = yield [("CD", [a, len(a_outgoing), b])]
     raise PrimitiveFinished(a)
 
@@ -241,61 +241,60 @@ def list_delete(a, b, **remainder):
     raise PrimitiveFinished(a)
 
 def list_read(a, b, **remainder):
-    b_value = yield [("RV", [b])]
-    result = yield [("RD", [a, b_value])]
+    b_value, = yield [("RV", [b])]
+    result, = yield [("RD", [a, b_value])]
     if result is None:
         raise Exception("List read out of bounds: %s" % b_value)
     raise PrimitiveFinished(result)
 
 def list_len(a, **remainder):
-    outgoings = yield [("RO", [a])]
-    result = yield [("CNV", [len(outgoings)])]
+    outgoings, = yield [("RO", [a])]
+    result, = yield [("CNV", [len(outgoings)])]
     raise PrimitiveFinished(result)
 
 def dict_add(a, b, c, **remainder):
-    new_edge = yield [("CE", [a, c])]
+    new_edge, = yield [("CE", [a, c])]
     yield [("CE", [new_edge, b])]
     raise PrimitiveFinished(a)
 
 def dict_delete(a, b, **remainder):
-    edge = yield [("RDNE", [a, b])]
+    edge, = yield [("RDNE", [a, b])]
     if edge is None:
         # This exact node isn't in this dictionary, so delete everything matching the value instead
-        b_value = yield [("RV", [b])]
-        edge = yield [("RDE", [a, b_value])]
+        b_value, = yield [("RV", [b])]
+        edge, = yield [("RDE", [a, b_value])]
     yield [("DE", [edge])]
-    print("DELETE " + str(edge))
     raise PrimitiveFinished(a)
 
 def dict_read(a, b, **remainder):
-    b_value = yield [("RV", [b])]
-    result = yield [("RD", [a, b_value])]
+    b_value, = yield [("RV", [b])]
+    result, = yield [("RD", [a, b_value])]
     raise PrimitiveFinished(result)
 
 def dict_read_edge(a, b, **remainder):
-    b_value = yield [("RV", [b])]
-    result = yield [("RDE", [a, b_value])]
+    b_value, = yield [("RV", [b])]
+    result, = yield [("RDE", [a, b_value])]
     raise PrimitiveFinished(result)
 
 def dict_read_node(a, b, **remainder):
-    result = yield [("RDN", [a, b])]
+    result, = yield [("RDN", [a, b])]
     raise PrimitiveFinished(result)
 
 def dict_in(a, b, **remainder):
-    b_value = yield [("RV", [b])]
-    value = yield [("RD", [a, b_value])]
+    b_value, = yield [("RV", [b])]
+    value, = yield [("RD", [a, b_value])]
     is_in = value is not None
-    result = yield [("CNV", [is_in])]
+    result, = yield [("CNV", [is_in])]
     raise PrimitiveFinished(result)
 
 def dict_in_node(a, b, **remainder):
-    value = yield [("RDN", [a, b])]
-    result = yield [("CNV", [value is not None])]
+    value, = yield [("RDN", [a, b])]
+    result, = yield [("CNV", [value is not None])]
     raise PrimitiveFinished(result)
 
 def dict_len(a, **remainder):
-    outgoings = yield [("RO", [a])]
-    result = yield [("CNV", [len(outgoings)])]
+    outgoings, = yield [("RO", [a])]
+    result, = yield [("CNV", [len(outgoings)])]
     raise PrimitiveFinished(result)
 
 def dict_keys(a, **remainder):
@@ -304,63 +303,59 @@ def dict_keys(a, **remainder):
     raise PrimitiveFinished(result)
 
 def dict_reverse(a, b, **remainder):
-    edges = yield [("RO", [a])]
-    expanded_edges = yield [("RE", [i]) for i in edges]
+    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]])]
+            outgoing, = yield [("RO", [edges[i]])]
+            result, = yield [("RE", [outgoing[0]])]
             raise PrimitiveFinished(result[1])
 
-    result = yield [("CNV", ["(unknown: %s)" % b])]
+    result, = yield [("CNV", ["(unknown: %s)" % b])]
     raise PrimitiveFinished(result)
 
 def is_physical_int(a, **remainder):
-    print("REQUEST PHYSICAL INT")
-    t = yield [("RV", [a])]
-    print(a)
-    print(t)
-    result = yield [("CNV", [isinstance(t, int) or isinstance(t, long)])]
-    print(type(t))
+    t, = yield [("RV", [a])]
+    result, = yield [("CNV", [isinstance(t, int) or isinstance(t, long)])]
     raise PrimitiveFinished(result)
 
 def is_physical_string(a, **remainder):
-    t = yield [("RV", [a])]
-    result = yield [("CNV", [isinstance(t, str) or isinstance(t, unicode)])]
+    t, = yield [("RV", [a])]
+    result, = yield [("CNV", [isinstance(t, str) or isinstance(t, unicode)])]
     raise PrimitiveFinished(result)
 
 def is_physical_float(a, **remainder):
-    t = yield [("RV", [a])]
-    result = yield [("CNV", [isinstance(t, float)])]
+    t, = yield [("RV", [a])]
+    result, = yield [("CNV", [isinstance(t, float)])]
     raise PrimitiveFinished(result)
 
 def is_physical_boolean(a, **remainder):
-    t = yield [("RV", [a])]
-    result = yield [("CNV", [isinstance(t, bool)])]
+    t, = yield [("RV", [a])]
+    result, = yield [("CNV", [isinstance(t, bool)])]
     raise PrimitiveFinished(result)
 
 def is_physical_action(a, **remainder):
-    t = yield [("RV", [a])]
-    result = yield [("CNV", [isinstance(t, dict) and t["value"] in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]])]
+    t, = yield [("RV", [a])]
+    result, = yield [("CNV", [isinstance(t, dict) and t["value"] in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]])]
     raise PrimitiveFinished(result)
 
 def create_node(**remainder):
-    result = yield [("CN", [])]
+    result, = yield [("CN", [])]
     raise PrimitiveFinished(result)
 
 def create_edge(a, b, **remainder):
-    result = yield [("CE", [a, b])]
+    result, = yield [("CE", [a, b])]
     raise PrimitiveFinished(result)
 
 def create_value(a, **remainder):
-    a_value = yield [("RV", [a])]
-    result = yield [("CNV", [a_value])]
+    a_value, = yield [("RV", [a])]
+    result, = yield [("CNV", [a_value])]
     raise PrimitiveFinished(result)
 
 def read_nr_out(a, **remainder):
-    outgoing = yield [("RO", [a])]
-    result = yield [("CNV", [len(outgoing)])]
+    outgoing, = yield [("RO", [a])]
+    result, = yield [("CNV", [len(outgoing)])]
     raise PrimitiveFinished(result)
 
 def read_out(a, b, **remainder):
@@ -368,8 +363,8 @@ def read_out(a, b, **remainder):
     raise PrimitiveFinished(sorted(outgoing)[b_value])
 
 def read_nr_in(a, **remainder):
-    incoming = yield [("RI", [a])]
-    result = yield [("CNV", [len(incoming)])]
+    incoming, = yield [("RI", [a])]
+    result, = yield [("CNV", [len(incoming)])]
     raise PrimitiveFinished(result)
 
 def read_in(a, b, **remainder):
@@ -377,25 +372,23 @@ def read_in(a, b, **remainder):
     raise PrimitiveFinished(sorted(incoming)[b_value])
 
 def read_edge_src(a, **remainder):
-    result = yield [("RE", [a])]
+    result, = yield [("RE", [a])]
     raise PrimitiveFinished(result[0])
 
 def read_edge_dst(a, **remainder):
-    result = yield [("RE", [a])]
+    result, = yield [("RE", [a])]
     raise PrimitiveFinished(result[1])
 
 def delete_element(a, **remainder):
-    edge = yield [("RE", [a])]
+    edge, = yield [("RE", [a])]
     if edge[0] is None:
         # Not an edge:
         yield [("DN", [a])]
-        print("DELETE ELEMENT NODE " + str(a))
-        result = yield [("CNV", [False])]
+        result, = yield [("CNV", [False])]
         raise PrimitiveFinished(result)
     else:
         yield [("DE", [a])]
-        print("DELETE ELEMENT EDGE " + str(a))
-        result = yield [("CNV", [True])]
+        result, = yield [("CNV", [True])]
         raise PrimitiveFinished(result)
 
 def read_root(root, **remainder):
@@ -406,21 +399,19 @@ def set_add(a, b, **remainder):
     raise PrimitiveFinished(a)
 
 def set_pop(a, **remainder):
-    outgoing = yield [("RO", [a])]
+    outgoing, = yield [("RO", [a])]
     v, _ = yield [("RE", [outgoing[0]]), ("DE", [outgoing[0]])]
     raise PrimitiveFinished(v[1])
 
 def set_remove(a, b, **remainder):
     outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
     elements = yield [("RE", [i]) for i in outgoing]
-    elements = [elements] if not isinstance(elements[0], list) else elements
     values = yield [("RV", [i[1]]) for i in elements]
-    values = [values] if not isinstance(values, list) else values
     yield [("DE", [identifier]) for identifier, edge in zip(outgoing, values) if edge == b_value]
     raise PrimitiveFinished(a)
 
 def set_remove_node(a, b, **remainder):
-    outgoing = yield [("RO", [a])]
+    outgoing, = yield [("RO", [a])]
     elements = yield [("RE", [i]) for i in outgoing]
     elements = [elements] if not isinstance(elements[0], list) else elements
     yield [("DE", [identifier]) for identifier, edge in zip(outgoing, elements) if edge[1] == b]
@@ -430,39 +421,36 @@ def set_in(a, b, **remainder):
     outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
     if outgoing:
         elements = yield [("RE", [i]) for i in outgoing]
-        elements = [elements] if not isinstance(elements[0], list) else elements
         values = yield [("RV", [i[1]]) for i in elements]
-        values = [values] if not isinstance(values, list) else values
         if b_value in [v for v in values]:
-            result = yield [("CNV", [True])]
+            result, = yield [("CNV", [True])]
         else:
-            result = yield [("CNV", [False])]
+            result, = yield [("CNV", [False])]
     else:
-        result = yield [("CNV", [False])]
+        result, = yield [("CNV", [False])]
     raise PrimitiveFinished(result)
 
 def set_in_node(a, b, **remainder):
-    outgoing = yield [("RO", [a])]
+    outgoing, = yield [("RO", [a])]
     if outgoing:
         elements = yield [("RE", [i]) for i in outgoing]
-        elements = [elements] if not isinstance(elements[0], list) else elements
         if b in [v[1] for v in elements]:
-            result = yield [("CNV", [True])]
+            result, = yield [("CNV", [True])]
         else:
-            result = yield [("CNV", [False])]
+            result, = yield [("CNV", [False])]
     else:
-        result = yield [("CNV", [False])]
+        result, = yield [("CNV", [False])]
     raise PrimitiveFinished(result)
 
 def is_edge(a, **remainder):
-    edge = yield [("RE", [a])]
-    result = yield [("CNV", [edge[0] is not None])]
+    edge, = yield [("RE", [a])]
+    result, = yield [("CNV", [edge[0] is not None])]
     raise PrimitiveFinished(result)
 
 #TODO deprecate
 def deserialize(a, root, **remainder):
     print("DESERIALIZE")
-    value = yield [("RV", [a])]
+    value, = yield [("RV", [a])]
     id_mappings = {}
     complex_primitives = frozenset(["if", "while", "assign", "call", "break", "continue", "return","resolve","access", "constant", "input", "output", "declare", "global"])
     for l in value.split("\n"):
@@ -472,7 +460,7 @@ def deserialize(a, root, **remainder):
             continue
         if graph_type == "N":
             # Node
-            id_mappings[constructor] = yield [("CN", [])]
+            id_mappings[constructor], = yield [("CN", [])]
         elif graph_type == "V":
             # Node with Value
             name, temp = constructor.split("(", 1)
@@ -482,16 +470,16 @@ def deserialize(a, root, **remainder):
             else:
                 #TODO this is very dangerous!
                 value = eval(string_value)
-            id_mappings[name] = yield [("CNV", [value])]
+            id_mappings[name], = yield [("CNV", [value])]
         elif graph_type == "E":
             # Edge
             name, temp = constructor.split("(", 1)
             source, target = temp[:-1].split(",", 1)
             if target[0] == "?" and target not in id_mappings:
                 hierarchy = target[1:].split("/")
-                current = yield [("RD", [root, "__hierarchy"])]
+                current, = yield [("RD", [root, "__hierarchy"])]
                 for i in hierarchy:
-                    current = yield [("RD", [current, i])]
+                    current, = yield [("RD", [current, i])]
                 id_mappings[target] = current
             try:
                 source = int(source)
@@ -502,7 +490,7 @@ def deserialize(a, root, **remainder):
             except:
                 target = id_mappings[target]
             # Both nodes will normally be already present in the matching dictionary, so can just pass them along
-            id_mappings[name] = yield [("CE", [source, target])]
+            id_mappings[name], = yield [("CE", [source, target])]
         elif graph_type == "D":
             source, value, target = constructor.split(",",3)
             if value in complex_primitives:
@@ -512,9 +500,9 @@ def deserialize(a, root, **remainder):
                 value = eval(value)
             if target[0] == "?" and target not in id_mappings:
                 hierarchy = target[1:].split("/")
-                current = yield [("RD", [root, "__hierarchy"])]
+                current, = yield [("RD", [root, "__hierarchy"])]
                 for i in hierarchy:
-                    current = yield [("RD", [current, i])]
+                    current, = yield [("RD", [current, i])]
                 id_mappings[target] = current
             try:
                 source = int(source)
@@ -530,6 +518,9 @@ def deserialize(a, root, **remainder):
     raise PrimitiveFinished(id_mappings["auto_initial_IP"])
 
 def log(a, **remainder):
-    a_value = yield [("RV", [a])]
+    a_value, = yield [("RV", [a])]
     print("== LOG == " + str(a_value))
     raise PrimitiveFinished(a)
+
+def read_userroot(user_root, **remainder):
+    raise PrimitiveFinished(user_root)

+ 0 - 2
kernel/test/utils.py

@@ -73,8 +73,6 @@ def execute_until_finished(mvk, mvs, operation="execute_rule", params=[]):
         response = []
         for command, param in mvs_commands:
             response.append(mvs.execute(command, param)[0])
-        if len(mvs_commands) == 1:
-            response = response[0]
 
 def get_inst(root, mvs):
     user_root = mvs.execute("RD", [root, "user_1"])[0]

+ 75 - 30
model/model.py

@@ -34,7 +34,7 @@ class MvSState(object):
     def __init__(self):
         self.queue = []
         self.output = None
-        self.mvs = MvS()
+        self.mvs = MvS("../bootstrap/bootstrap.m")
         self.timer = float("inf")
 
 class ModelverseState(AtomicDEVS):
@@ -91,9 +91,8 @@ class ModelverseState(AtomicDEVS):
             # And already compute the result so it is ready to output
             self.state.output = []
             self.state.timer = 0.0
-            print("Got input: " + str(inputs[self.from_mvk]))
             for v in self.state.queue[0]:
-                self.state.output.append(getattr(self.state.mvs, translate(v[0]))(*v[1])[0])
+                self.state.output.append(getattr(self.state.mvs, translate(v[0]))(*v[1]))
                 self.state.timer += self.timings[translate(v[0])]()
         else:
             # Just append the message to process
@@ -125,12 +124,15 @@ class MvKState(object):
     def __init__(self):
         self.mvk = None
         self.waiting = False
-        self.inputs = []
-        self.outputs = []
+        self.inputs = {}
+        self.outputs = {}
         self.users = []
         self.reply = None
         self.phase = None
         self.commands = None
+        self.root = None
+        self.current_user = None
+        self.loaded_primitives = False
 
     def __str__(self):
         return "\nMvK: %s\n" % self.mvk + \
@@ -140,7 +142,9 @@ class MvKState(object):
                 "users: %s\n" % self.users + \
                 "reply: %s\n" % self.reply + \
                 "phase: %s\n" % self.phase + \
-                "commands: %s\n" % self.commands
+                "commands: %s\n" % self.commands + \
+                "root: %s\n" % self.root + \
+                "current user: %s\n" % self.current_user
 
 class ModelverseKernel(AtomicDEVS):
     def __init__(self):
@@ -156,23 +160,29 @@ class ModelverseKernel(AtomicDEVS):
         if self.from_mvi in inputs:
             # Got input from MvI, so we queue it
             for inp in inputs[self.from_mvi]:
-                if inp is not None:
-                    self.state.inputs.append(inp)
+                username = inp[0]
+                data = inp[1]
+                if data is not None:
+                    self.state.inputs.setdefault(username, []).extend(data)
                 else:
-                    self.state.outputs.append(None)
+                    self.state.outputs.setdefault(username, []).append(None)
 
         if self.from_mvs in inputs:
             # Got input from MvS, so we can continue processing
-            if self.state.mvk is None:
-                # No MvK, so set it with the root we have just received (or should have received)
-                self.state.mvk = MvK(inputs[self.from_mvs][0])
-            else:
-                self.state.reply = inputs[self.from_mvs][0]
+            for mvs_input in inputs[self.from_mvs]:
+                mvs_stripped = [i[0] for i in mvs_input]
+                if self.state.mvk is None:
+                    # No MvK, so set it with the root we have just received (or should have received)
+                    self.state.root = mvs_stripped[0]
+                    self.state.mvk = MvK(self.state.root)
+                else:
+                    self.state.reply = mvs_stripped
             self.state.waiting = False
 
         return self.state
 
     def intTransition(self):
+        was_empty = len(self.state.users) == 0
         if self.state.commands is not None:
             self.state.commands = None
             return self.state
@@ -180,36 +190,62 @@ class ModelverseKernel(AtomicDEVS):
         if self.state.mvk is None:
             # Initializing
             self.state.waiting = True
+        elif not self.state.loaded_primitives:
+            commands = self.state.mvk.execute_yields("", "load_primitives", [], self.state.reply)
+            if commands is None:
+                self.state.loaded_primitives = True
+                self.state.reply = None
+            else:
+                self.state.waiting = True
+            self.state.commands = commands
         else:
             # Are initialized and have work to do
             if len(self.state.users) == 0:
                 # Read out new set of users first
                 if self.state.reply is None:
-                    commands = [("RDK", [])]
+                    commands = [("RDK", [self.state.root])]
+                else:
+                    self.state.users = self.state.reply
+                    commands = None
+            elif self.state.phase == "init_user":
+                if self.state.reply is None:
+                    commands = [("RV", [self.state.users[0]])]
                 else:
-                    self.users = self.state.reply
-                    print("Got users: " + str(self.users))
+                    self.state.current_user = self.state.reply
+                    if self.state.current_user.startswith("__"):
+                        # Don't process this user and force termination of user
+                        self.state.phase = "output"
                     commands = None
             elif self.state.phase == "input":
                 # Process inputs
-                commands = self.state.mvk.execute_yields(self.state.users[0], "set_input", [self.state.inputs[0]], self.state.reply)
+                if self.state.inputs.get(self.state.current_user, None):
+                    element_type, value = self.state.inputs[self.state.current_user][0]
+                    commands = self.state.mvk.execute_yields(self.state.current_user, "set_input", [element_type, value], self.state.reply)
+                    if commands is None:
+                        self.state.inputs[self.state.current_user].pop(0)
+                else:
+                    commands = None
+
             elif self.state.phase == "computation":
-                commands = self.state.mvk.execute_yields(self.state.users[0], "execute_rule", [], self.state.reply)
+                commands = self.state.mvk.execute_yields(self.state.current_user, "execute_rule", [], self.state.reply)
             elif self.state.phase == "output":
-                commands = self.state.mvk.execute_yields(self.state.users[0], "get_output", [], self.state.reply)
+                commands = self.state.mvk.execute_yields(self.state.current_user, "get_output", [], self.state.reply)
+            else:
+                raise Exception("Phase: " + str(self.state.phase))
 
             # Advance phase
             if commands is None:
-                if len(self.state.users) == 0:
+                if was_empty:
+                    self.state.phase = "init_user"
+                elif self.state.phase == "init_user":
                     self.state.phase = "input"
                 elif self.state.phase == "input":
-                    self.state.inputs.pop(0)
                     self.state.phase = "computation"
                 elif self.state.phase == "computation":
                     self.state.phase = "output"
                 elif self.state.phase == "output":
                     self.state.users.pop(0)
-                    self.state.phase = "input"
+                    self.state.phase = "init_user"
                 self.state.waiting = False
                 self.state.reply = None
             else:
@@ -229,7 +265,7 @@ class ModelverseKernel(AtomicDEVS):
         return {}
 
     def timeAdvance(self):
-        if self.state.commands:
+        if self.state.commands is not None:
             return 0
         elif self.state.waiting:
             return float("inf")
@@ -247,10 +283,11 @@ class MvIState():
         self.init = True
 
 class ModelverseInterface(AtomicDEVS):
-    def __init__(self, operations):
-        AtomicDEVS.__init__(self, "MvI")
+    def __init__(self, username, operations):
+        AtomicDEVS.__init__(self, "MvI_%s" % username)
         self.state = MvIState()
         self.state.operations = operations
+        self.username = username
 
         self.to_mvk = self.addOutPort("to_MvK")
         self.from_mvk = self.addInPort("from_MvK")
@@ -282,7 +319,7 @@ class ModelverseInterface(AtomicDEVS):
                 send.append(("R", self.memory[i]))
             elif not isinstance(i, int):
                 send.append(("V", i))
-        return {self.to_mvk: [send]}
+        return {self.to_mvk: [(self.username, send)]}
 
     def timeAdvance(self):
         if self.state.init:
@@ -334,6 +371,7 @@ class Network(AtomicDEVS):
 
 class System(CoupledDEVS):
     def __init__(self,
+                username,
                 operations,
                 mvi2mvk_latency,
                 mvi2mvk_bandwidth,
@@ -362,7 +400,12 @@ class System(CoupledDEVS):
                 delete_edge):
         CoupledDEVS.__init__(self, "System")
 
+        self.mvi_manager = self.addSubModel(ModelverseInterface(\
+                            username            = "user_manager",
+                            operations          = [username],
+                        ))
         self.mvi = self.addSubModel(ModelverseInterface(\
+                            username            = username,
                             operations          = operations
                         ))
         self.mvk = self.addSubModel(ModelverseKernel())
@@ -406,6 +449,7 @@ class System(CoupledDEVS):
                             bandwidth   = mvk2mvi_bandwidth
                         ))
 
+        self.connectPorts(self.mvi_manager.to_mvk, self.mvk.from_mvi)
         self.connectPorts(self.mvi.to_mvk, self.mvi2mvk.input_port)
         self.connectPorts(self.mvi2mvk.output_port, self.mvk.from_mvi)
         self.connectPorts(self.mvk.to_mvs, self.mvk2mvs.input_port)
@@ -420,7 +464,8 @@ operations = [
     ]
 
 args = {
-        "operations": operations,
+        "username":             "test_user",
+        "operations":           operations,
         "mvi2mvk_latency":      1,
         "mvi2mvk_bandwidth":    2000,
         "mvk2mvs_latency":      1,
@@ -450,6 +495,6 @@ args = {
 
 model = System(**args)
 sim = Simulator(model)
-sim.setTerminationTime(10)
-sim.setVerbose()
+sim.setTerminationTime(90000)
+#sim.setVerbose()
 sim.simulate()

+ 3 - 3
scripts/prompt.py

@@ -93,11 +93,11 @@ while 1:
 
     if command.startswith("$"):
         # Invoke the HUTN parser
-        tmp_file = "__constraint.al"
+        tmp_file = "__action.alc"
         with open(tmp_file, 'w') as f:
-            f.write("Element function constraint(model : Element, element_name : String):\n")
+            f.write("")
         local_print("Entering HUTN coding environment.")
-        local_print("There is no nice editor right now, so please just modify the file '__constraint.al' in this folder.")
+        local_print("There is no nice editor right now, so please just modify the file '__action.alc' in this folder.")
         while 1:
             local_print("When you are done, press <return> to continue.")
             raw_input()