Przeglądaj źródła

Initial commit from svn

Yentl Van Tendeloo 9 lat temu
commit
e527d9b485
100 zmienionych plików z 19077 dodań i 0 usunięć
  1. 320 0
      bootstrap/bootstrap.py
  2. 63 0
      bootstrap/compilation_manager.alc
  3. 315 0
      bootstrap/conformance_scd.alc
  4. 430 0
      bootstrap/constructors.alc
  5. 37 0
      bootstrap/library.alc
  6. 195 0
      bootstrap/object_operations.alc
  7. 114 0
      bootstrap/primitives.alc
  8. 11 0
      compile.sh
  9. 13 0
      fix_linux.sh
  10. 12 0
      fix_windows.bat
  11. 2 0
      flush_compiler_caches.sh
  12. 3 0
      generate_bootstrap.sh
  13. 198 0
      hybrid_server/classes/mvkcontroller.xml
  14. 110 0
      hybrid_server/classes/server.xml
  15. 154 0
      hybrid_server/classes/socket.xml
  16. 2 0
      hybrid_server/compile.sh
  17. 17 0
      hybrid_server/python_runtime/.project
  18. 5 0
      hybrid_server/python_runtime/.pydevproject
  19. 0 0
      hybrid_server/python_runtime/__init__.py
  20. 9 0
      hybrid_server/python_runtime/accurate_time.py
  21. 58 0
      hybrid_server/python_runtime/event_queue.py
  22. 3 0
      hybrid_server/python_runtime/infinity.py
  23. 1 0
      hybrid_server/python_runtime/libs/__init__.py
  24. 59 0
      hybrid_server/python_runtime/libs/drawing.py
  25. 107 0
      hybrid_server/python_runtime/libs/ui.py
  26. 19 0
      hybrid_server/python_runtime/libs/utils.py
  27. 22 0
      hybrid_server/python_runtime/nextafter.py
  28. 941 0
      hybrid_server/python_runtime/statecharts_core.py
  29. 21 0
      hybrid_server/python_runtime/tkinter_eventloop.py
  30. 17 0
      hybrid_server/python_sccd_compiler/.project
  31. 5 0
      hybrid_server/python_sccd_compiler/.pydevproject
  32. 0 0
      hybrid_server/python_sccd_compiler/__init__.py
  33. 14 0
      hybrid_server/python_sccd_compiler/compiler_exceptions.py
  34. 911 0
      hybrid_server/python_sccd_compiler/generic_generator.py
  35. 990 0
      hybrid_server/python_sccd_compiler/generic_language_constructs.py
  36. 285 0
      hybrid_server/python_sccd_compiler/javascript_writer.py
  37. 170 0
      hybrid_server/python_sccd_compiler/lexer.py
  38. 701 0
      hybrid_server/python_sccd_compiler/old_generators/csharp_generator.py
  39. 741 0
      hybrid_server/python_sccd_compiler/old_generators/javascript_generator.py
  40. 644 0
      hybrid_server/python_sccd_compiler/old_generators/python_generator.py
  41. 81 0
      hybrid_server/python_sccd_compiler/path_calculator.py
  42. 353 0
      hybrid_server/python_sccd_compiler/python_writer.py
  43. 1131 0
      hybrid_server/python_sccd_compiler/sccd_constructs.py
  44. 129 0
      hybrid_server/python_sccd_compiler/sccdc.py
  45. 156 0
      hybrid_server/python_sccd_compiler/state_linker.py
  46. 222 0
      hybrid_server/python_sccd_compiler/stateful_writer.py
  47. 52 0
      hybrid_server/python_sccd_compiler/super_class_linker.py
  48. 118 0
      hybrid_server/python_sccd_compiler/utils.py
  49. 30 0
      hybrid_server/python_sccd_compiler/visitor.py
  50. 4 0
      hybrid_server/run.sh
  51. 19 0
      hybrid_server/run_mvk_server.py
  52. 1379 0
      hybrid_server/server.py
  53. 27 0
      hybrid_server/server.xml
  54. 117 0
      hybrid_server/socket2event.py
  55. 151 0
      integration/code/b2dc.txt
  56. 23 0
      integration/code/binary_to_decimal.alc
  57. 11 0
      integration/code/factorial.alc
  58. 11 0
      integration/code/fibonacci.alc
  59. 17 0
      integration/code/fibonacci_smart.alc
  60. 12 0
      integration/code/if_elif.alc
  61. 13 0
      integration/code/if_elif_else.alc
  62. 27 0
      integration/code/import_metamodel.alc
  63. 326 0
      integration/code/import_metamodel_cs.txt
  64. 16 0
      integration/code/leap_year.alc
  65. 4 0
      integration/code/lib_remainder.alc
  66. 6 0
      integration/code/main.alc
  67. 556 0
      integration/code/pn_interface.alc
  68. 11 0
      integration/code/power.alc
  69. 5 0
      integration/code/remainder.alc
  70. 21 0
      integration/code/revert.alc
  71. 17 0
      integration/test_binary2decimal.py
  72. 328 0
      integration/test_constructors_al.py
  73. 348 0
      integration/test_constructors_al_linkable.py
  74. 1933 0
      integration/test_constructors_models.py
  75. 17 0
      integration/test_factorial.py
  76. 17 0
      integration/test_fibonacci.py
  77. 17 0
      integration/test_fibonacci_smart.py
  78. 29 0
      integration/test_if_elif.py
  79. 17 0
      integration/test_leap_year.py
  80. 17 0
      integration/test_main.py
  81. 672 0
      integration/test_pn_interface.py
  82. 16 0
      integration/test_power.py
  83. 16 0
      integration/test_remainder.py
  84. 17 0
      integration/test_revert.py
  85. 216 0
      integration/utils.py
  86. 212 0
      interface/HUTN/grammars/actionlanguage.g
  87. 34 0
      interface/HUTN/grammars/modellanguage.g
  88. 0 0
      interface/HUTN/hutn_compiler/__init__.py
  89. 46 0
      interface/HUTN/hutn_compiler/bootstrap_visitor.py
  90. 222 0
      interface/HUTN/hutn_compiler/compiler.py
  91. 124 0
      interface/HUTN/hutn_compiler/constructors_object_visitor.py
  92. 296 0
      interface/HUTN/hutn_compiler/constructors_visitor.py
  93. 43 0
      interface/HUTN/hutn_compiler/declare_functions_visitor.py
  94. 340 0
      interface/HUTN/hutn_compiler/grammar_compiler_visitor.py
  95. 976 0
      interface/HUTN/hutn_compiler/hutnparser.py
  96. 93 0
      interface/HUTN/hutn_compiler/linker.py
  97. 78 0
      interface/HUTN/hutn_compiler/loader.py
  98. 116 0
      interface/HUTN/hutn_compiler/meta_grammar.py
  99. 73 0
      interface/HUTN/hutn_compiler/position.py
  100. 0 0
      interface/HUTN/hutn_compiler/prettyprint_visitor.py

+ 320 - 0
bootstrap/bootstrap.py

@@ -0,0 +1,320 @@
+### Configuration for creating the bootstrap model using conformance_bottom.
+
+root = ["__hierarchy"]
+
+user_data = [   "input",
+                "output",
+                "globals",
+                "frame",
+                ]
+
+user_frame = [  "evalstack",
+                "symbols",
+                "returnvalue",
+                ]
+
+primitives = {  "integer_addition": ["Integer", "Integer", "Integer"],
+                "integer_subtraction": ["Integer", "Integer", "Integer"],
+                "integer_multiplication": ["Integer", "Integer", "Integer"],
+                "integer_division": ["Integer", "Integer", "Integer"],
+                "integer_gt": ["Boolean", "Integer", "Integer"],
+                "integer_gte": ["Boolean", "Integer", "Integer"],
+                "integer_lt": ["Boolean", "Integer", "Integer"],
+                "integer_lte": ["Boolean", "Integer", "Integer"],
+                "integer_eq": ["Boolean", "Integer", "Integer"],
+                "integer_neq": ["Boolean", "Integer", "Integer"],
+                "integer_neg": ["Integer", "Integer"],
+                "float_addition": ["Float", "Float", "Float"],
+                "float_subtraction": ["Float", "Float", "Float"],
+                "float_multiplication": ["Float", "Float", "Float"],
+                "float_division": ["Float", "Float", "Float"],
+                "float_gt": ["Boolean", "Float", "Float"],
+                "float_gte": ["Boolean", "Float", "Float"],
+                "float_lt": ["Boolean", "Float", "Float"],
+                "float_lte": ["Boolean", "Float", "Float"],
+                "float_eq": ["Boolean", "Float", "Float"],
+                "float_neq": ["Boolean", "Float", "Float"],
+                "float_neg": ["Float", "Float"],
+                "bool_and": ["Boolean", "Boolean", "Boolean"],
+                "bool_or": ["Boolean", "Boolean", "Boolean"],
+                "bool_not": ["Boolean", "Boolean"],
+                "bool_eq": ["Boolean", "Boolean", "Boolean"],
+                "bool_neq": ["Boolean", "Boolean", "Boolean"],
+                "string_join": ["String", "String", "String"],
+                "string_get": ["String", "String", "Integer"],
+                "string_substr": ["String", "String", "Integer", "Integer"],
+                "string_len": ["Integer", "String"],
+                "string_split": ["Element", "String", "String"],
+                "string_startswith": ["Boolean", "String", "String"],
+                "string_eq": ["Boolean", "String", "String"],
+                "string_neq": ["Boolean", "String", "String"],
+                "action_eq": ["Boolean", "Action", "Action"],
+                "action_neq": ["Boolean", "Action", "Action"],
+                "type_eq": ["Boolean", "Type", "Type"],
+                "type_neq": ["Boolean", "Type", "Type"],
+                "cast_i2f": ["Float", "Integer"],
+                "cast_i2s": ["String", "Integer"],
+                "cast_i2b": ["Boolean", "Integer"],
+                "cast_f2i": ["Integer", "Float"],
+                "cast_f2b": ["Boolean", "Float"],
+                "cast_f2s": ["String", "Float"],
+                "cast_s2i": ["Integer", "String"],
+                "cast_s2f": ["Float", "String"],
+                "cast_s2b": ["Boolean", "String"],
+                "cast_b2i": ["Integer", "Boolean"],
+                "cast_b2f": ["Float", "Boolean"],
+                "cast_b2s": ["String", "Boolean"],
+                "cast_e2s": ["String", "Element"],
+                "cast_t2s": ["String", "Type"],
+                "cast_a2s": ["String", "Action"],
+                "cast_v2s": ["String", "Element"],
+                "cast_id2s": ["String", "Element"],
+                "list_read": ["Element", "Element", "Integer"],
+                "list_append": ["Element", "Element", "Element"],
+                "list_insert": ["Element", "Element", "Integer", "Element"],
+                "list_delete": ["Element", "Element", "Integer"],
+                "list_len": ["Integer", "Element"],
+                "dict_add": ["Element", "Element", "Element", "Element"],
+                "dict_delete": ["Element", "Element", "Element"],
+                "dict_read": ["Element", "Element", "Element"],
+                "dict_read_edge": ["Element", "Element", "Element"],
+                "dict_read_node": ["Element", "Element", "Element"],
+                "dict_len": ["Integer", "Element"],
+                "dict_in": ["Boolean", "Element", "Element"],
+                "dict_in_node": ["Boolean", "Element", "Element"],
+                "dict_keys": ["Element", "Element"],
+                "set_add": ["Element", "Element", "Element"],
+                "set_pop": ["Element", "Element"],
+                "set_remove": ["Element", "Element", "Element"],
+                "set_remove_node": ["Element", "Element", "Element"],
+                "set_in": ["Boolean", "Element", "Element"],
+                "set_in_node": ["Boolean", "Element", "Element"],
+                "typeof": ["Type", "Element"],
+                "create_node": ["Element"],
+                "create_edge": ["Element", "Element", "Element"],
+                "create_value": ["Element", "Element"],
+                "is_edge": ["Boolean", "Element"],
+                "read_nr_out": ["Integer", "Element"],
+                "read_out": ["Element", "Element", "Integer"],
+                "read_nr_in": ["Integer", "Element"],
+                "read_in": ["Element", "Element", "Integer"],
+                "read_edge_src": ["Element", "Element"],
+                "read_edge_dst": ["Element", "Element"],
+                "delete_element": ["Element", "Element"],
+                "element_eq": ["Boolean", "Element", "Element"],
+                "element_neq": ["Boolean", "Element", "Element"],
+                "read_root": ["Element"],
+                "deserialize": ["Element", "String"],
+                "log": ["Element", "String"],
+            }
+
+initial_user = "user_manager"
+initial_user_code = \
+'''
+Element function read_root() = ?primitives/read_root
+Element function dict_read(a: Element, b: Element) = ?primitives/dict_read
+Element function create_node() = ?primitives/create_node
+Element function create_value(a: Element) = ?primitives/create_value
+Element function dict_add(a: Element, b: Element, c: Element) = ?primitives/dict_add
+Boolean function string_eq(a: String, b: String) = ?primitives/string_eq
+Boolean function delete_element(a: Element) = ?primitives/delete_element
+Boolean function bool_not(a: Boolean) = ?primitives/bool_not
+Boolean function dict_in(a: Element, b: Element) = ?primitives/dict_in
+
+Element function input()
+
+Void function __main():
+\tString username
+\tElement user_root
+\tElement user_frame
+\tElement output_value
+\tElement input_value
+\t
+\twhile (True):
+\t\tusername = input()
+\t\tif (string_eq(username, "__delete")):
+\t\t\tuser_root = dict_read(read_root(), input())
+\t\t\tdelete_element(user_root)
+\t\telse:
+\t\t\tif (bool_not(dict_in(read_root(), username))):
+\t\t\t\tuser_root = create_node()
+\t\t\t\tuser_frame = create_node()
+\t\t\t\toutput_value = create_node()
+\t\t\t\tinput_value = create_node()
+\t\t\t\tdict_add(user_root, "frame", user_frame)
+\t\t\t\tdict_add(user_root, "globals", create_node())
+\t\t\t\tdict_add(user_root, "output", output_value)
+\t\t\t\tdict_add(user_root, "last_output", output_value)
+\t\t\t\tdict_add(user_root, "input", input_value)
+\t\t\t\tdict_add(user_root, "last_input", input_value)
+\t\t\t\tdict_add(user_frame, "evalstack", create_node())
+\t\t\t\tdict_add(user_frame, "returnvalue", create_node())
+\t\t\t\tdict_add(user_frame, "phase", "init")
+\t\t\t\tdict_add(user_frame, "IP", dict_read(dict_read(read_root(), "__hierarchy"), "__IP"))
+\t\t\t\tdict_add(user_frame, "symbols", create_node())
+\t\t\t\t//Add this only at the end, as otherwise the user will already be detected
+\t\t\t\tdict_add(read_root(), username, user_root)
+'''
+
+code_new_users = \
+'''
+Element main
+
+include "io.alh"
+include "primitives.alc"
+include "compilation_manager.alc"
+include "constructors.alc"
+include "conformance_scd.alc"
+include "object_operations.alc"
+include "library.alc"
+
+Void function __main():
+\tInteger interface
+\twhile (True):
+\t\tinterface = input()
+\t\tif (integer_eq(interface, 0)):
+\t\t\tlog("DO deserialize")
+\t\t\texec(deserialize(input()))
+\t\telif (integer_eq(interface, 1)):
+\t\t\texec(construct_unknown())
+\t\telif (integer_eq(interface, 3)):
+\t\t\tcompilation_manager()
+\t\telse:
+\t\t\tlog("Unsupported interface!")
+'''
+
+### Actual script to generate the file
+import os
+import sys
+
+class Writer(object):
+    def __init__(self, file_a, file_b):
+        self.file_a = file_a
+        self.file_b = file_b
+
+    def write(self, text, both=True):
+        self.file_a.write(text)
+        if both:
+            self.file_b.write(text)
+
+try:
+    with open("bootstrap.m", "w") as fa:
+        with open("minimal.m", "w") as fb:
+            f = Writer(fa, fb)
+            # Create the root first
+            f.write("Node root()\n")
+
+            # Create all children of the root
+            for node in root:
+                f.write("Node %s()\n" % node)
+                f.write("Edge _%s(root, %s)\n" % (node, node))
+                f.write('Node __%s("%s")\n' % (node, node))
+                f.write("Edge ___%s(_%s, __%s)\n" % (node, node, node))
+
+            f.write("Node primitives()\n")
+            f.write("Edge _primitives(__hierarchy, primitives)\n")
+            f.write('Node __primitives("primitives")\n')
+            f.write("Edge ___primitives(_primitives, __primitives)\n")
+
+            # Define all primitive functions
+            for function, parameters in primitives.iteritems():
+                if parameters[0] == "Element":
+                    f.write("Node _type_%s()\n" % function)
+                else:
+                    f.write("Node _type_%s(%s)\n" % (function, parameters[0]))
+                    
+                f.write("Node _func_signature_%s()\n" % function)
+                f.write("Node _func_params_%s()\n" % function)
+                f.write("Node _func_body_%s()\n" % function)
+                f.write("Edge _primitives_%s(primitives, _func_signature_%s)\n" % (function, function))
+                f.write('Node _name_%s("%s")\n' % (function, function))
+                f.write("Edge _primitives_name_%s(_primitives_%s, _name_%s)\n" % (function, function, function))
+
+                f.write('Node _body_%s("body")\n' % function)
+                f.write("Edge _signature_body_%s(_func_signature_%s, _func_body_%s)\n" % (function, function, function))
+                f.write("Edge _signature_body_str_%s(_signature_body_%s, _body_%s)\n" % (function, function, function))
+
+                f.write('Node _params_%s("params")\n' % function)
+                f.write("Edge _signature_params_%s(_func_signature_%s, _func_params_%s)\n" % (function, function, function))
+                f.write("Edge _signature_params_str_%s(_signature_params_%s, _params_%s)\n" % (function, function, function))
+
+                f.write('Node _type_str_%s("type")\n' % function)
+                f.write("Edge _signature_type_%s(_func_signature_%s, _type_%s)\n" % (function, function, function))
+                f.write("Edge _signature_type_str_%s(_signature_type_%s, _type_str_%s)\n" % (function, function, function))
+
+                parameter_names = "abcdefghijklmnopqrstuvwxyz"
+                for number, param in enumerate(parameters[1:]):
+                    param_encoding = "%s_%s" % (function, parameter_names[number])
+                    if param == "Element":
+                        f.write("Node _type_%s()\n" % param_encoding)
+                    else:
+                        f.write("Node _type_%s(%s)\n" % (param_encoding, param))
+
+                    f.write("Node _func_params_%s()\n" % (param_encoding))
+                    f.write('Node _name_%s("%s")\n' % (param_encoding, parameter_names[number]))
+                    f.write("Edge _param_link_%s(_func_params_%s, _func_params_%s)\n" % (param_encoding, function, param_encoding))
+                    f.write("Edge _param_link_str_%s(_param_link_%s, _name_%s)\n" % (param_encoding, param_encoding, param_encoding))
+                    f.write('Node _name_str_%s("name")\n' % param_encoding)
+                    f.write("Edge _param_name_%s(_func_params_%s, _name_%s)\n" % (param_encoding, param_encoding, param_encoding))
+                    f.write("Edge _param_name_str_%s(_param_name_%s, _name_str_%s)\n" % (param_encoding, param_encoding, param_encoding))
+                    f.write('Node _type_str_%s("type")\n' % param_encoding)
+                    f.write("Edge _param_type_%s(_func_params_%s, _type_%s)\n" % (param_encoding, param_encoding, param_encoding))
+                    f.write("Edge _param_type_str_%s(_param_type_%s, _type_str_%s)\n" % (param_encoding, param_encoding, param_encoding))
+
+            # Create the initial user
+            f.write("Node user_root()\n")
+
+            for data in user_data:
+                f.write("Node user_%s()\n" % data)
+                f.write('Node ___user_%s("%s")\n' % (data, data))
+                f.write("Edge _user_%s(user_root, user_%s)\n" % (data, data))
+                f.write("Edge __user_%s(_user_%s, ___user_%s)\n" % (data, data, data))
+
+            for data in user_frame:
+                f.write("Node user_%s()\n" % data)
+                f.write('Node ___user_%s("%s")\n' % (data, data))
+                f.write("Edge _user_%s(user_frame, user_%s)\n" % (data, data))
+                f.write("Edge __user_%s(_user_%s, ___user_%s)\n" % (data, data, data))
+
+            # Add last_input and last_output links
+            for data in ["input", "output"]:
+                f.write('Node ___user_last_%s("last_%s")\n' % (data, data))
+                f.write("Edge _user_last_%s(user_root, user_%s)\n" % (data, data))
+                f.write("Edge __user_last_%s(_user_last_%s, ___user_last_%s)\n" % (data, data, data))
+                
+            # Bind user to the root
+            f.write('Node ___new_user("%s")\n' % initial_user)
+            f.write("Edge _new_user(root, user_root)\n")
+            f.write("Edge __new_user(_new_user, ___new_user)\n")
+
+            def compile_code_AL(code, target):
+                import sys
+                sys.path.append("../interface/HUTN/")
+                from hutn_compiler.compiler import main as compile_code
+
+                with open("bootstrap.al", "w") as f:
+                    f.write(code)
+                code = compile_code("bootstrap.al", "../interface/HUTN/grammars/actionlanguage.g", "BS", [])
+                os.remove("bootstrap.al")
+                return code.replace("auto_initial_IP", target)
+
+            # Create code for initial user
+            f.write(compile_code_AL(initial_user_code, "IP_initial"), both=False)
+            f.write('Node _IP_str("IP")\n', both=False)
+            f.write("Edge _user_frame(user_frame, IP_initial)\n", both=False)
+            f.write("Edge __user_frame(_user_frame, _IP_str)\n", both=False)
+
+            f.write('Node __phase("init")\n', both=False)
+            f.write('Node __phase_str("phase")\n', both=False)
+            f.write("Edge _user_phase(user_frame, __phase)\n", both=False)
+            f.write("Edge __user_phase(_user_phase, __phase_str)\n", both=False)
+
+            # Create code for new users to start at
+            f.write(compile_code_AL(code_new_users, "IP_new"), both=False)
+            f.write('Node __IP_str("__IP")\n', both=False)
+            f.write("Edge _user_IP(__hierarchy, IP_new)\n", both=False)
+            f.write("Edge __user_IP(_user_IP, __IP_str)\n", both=False)
+except:
+    os.remove("bootstrap.m")
+    os.remove("minimal.m")
+    raise

+ 63 - 0
bootstrap/compilation_manager.alc

@@ -0,0 +1,63 @@
+include "primitives.alh"
+include "constructors.alh"
+
+Element function compilation_manager():
+	String op_com
+	String name_com
+	Boolean defines_com
+	Element elem_com
+	Element root_com
+	Element node_com
+	Element symbols_com
+	Element keys_com
+	Integer nr_com
+	Integer i_com
+
+	if (dict_in(dict_read(read_root(), "__hierarchy"), "objects")):
+		root_com = dict_read(dict_read(read_root(), "__hierarchy"), "objects")
+	else:
+		root_com = create_node()
+		dict_add(dict_read(read_root(), "__hierarchy"), "objects", root_com)
+
+	op_com = input()
+	if (string_eq(op_com, "upload")):
+		name_com = input()
+		node_com = create_node()
+		dict_add(root_com, name_com, node_com)
+		dict_add(node_com, "hash_md5", input())
+		if (input()):
+			dict_add(node_com, "initializers", construct_top())
+		else:
+			dict_add(node_com, "initializers", deserialize(input()))
+
+		symbols_com = create_node()
+		dict_add(node_com, "symbols", symbols_com)
+		while (input()):
+			dict_add(symbols_com, input(), input())
+	elif (string_eq(op_com, "read_symbols")):
+		name_com = input()
+		node_com = dict_read(dict_read(root_com, name_com), "symbols")
+		keys_com = dict_keys(node_com)
+		String rv
+		rv = ""
+		while (integer_lt(0, read_nr_out(keys_com))):
+			elem_com = set_pop(keys_com)
+			if (dict_read(node_com, elem_com)):
+				rv = string_join(rv, string_join(elem_com, ":1\n"))
+			else:
+				rv = string_join(rv, string_join(elem_com, ":0\n"))
+		output(rv)
+	elif (string_eq(op_com, "read_initializers")):
+		node_com = dict_read(dict_read(root_com, input()), "initializers")
+		output(node_com)
+	elif (string_eq(op_com, "remove_obj")):
+		dict_delete(root_com, input())
+	elif (string_eq(op_com, "is_defined")):
+		name_com = input()
+		if (dict_in(root_com, name_com)):
+			output(dict_read(dict_read(root_com, name_com), "hash_md5"))
+		else:
+			output(create_node())
+	else:
+		log("Failed to understand command")
+	return op_com

+ 315 - 0
bootstrap/conformance_scd.alc

@@ -0,0 +1,315 @@
+include "primitives.alh"
+include "library.alh"
+include "object_operations.alh"
+include "constructors.alh"
+
+Element function set_copy(elem_to_copy : Element):
+	Element result
+	Integer counter_copy
+	Integer max
+
+	result = create_node()
+
+	// Expand the provided list by including all elements that need to be checked
+	counter_copy = 0
+	max = read_nr_out(elem_to_copy)
+	while (integer_lt(counter_copy, max)):
+		set_add(result, read_edge_dst(read_out(elem_to_copy, counter_copy)))
+		counter_copy = integer_addition(counter_copy, 1)
+
+	return result
+
+Boolean function is_direct_instance(model_idi : Element, instance_idi : Element, type_idi : Element):
+	// Just check whether or not the type mapping specifies the type as the type of the instance
+	return element_eq(dict_read_node(dict_read(model_idi, "type_mapping"), instance_idi), type_idi)
+
+Boolean function is_nominal_instance(model_ini : Element, instance_ini : Element, type_ini : Element):
+	return is_nominal_subtype(type_ini, dict_read_node(dict_read(model_ini, "type_mapping"), instance_ini), dict_read(dict_read(model_ini, "metamodel"), "type_mapping"), dict_read(model_ini, "inheritance"))
+
+Boolean function is_nominal_subtype(superclass : Element, subclass : Element, types : Element, inheritance_link : Element):
+	Integer counter_iso
+	Integer i_iso
+	Element edge_iso
+	Element destination_iso
+
+	// End of recursion
+	if (element_eq(superclass, subclass)):
+		return True
+
+	// Iterate over all superclasses of the found class
+	counter_iso = read_nr_out(subclass)
+	i_iso = 0
+	while (integer_lt(i_iso, counter_iso)):
+		edge_iso = read_out(subclass, i_iso)
+		// Check if it even has a type (to prevent errors)
+		if (dict_in_node(types, edge_iso)):
+			// Check whether it is an inheritance edge, as there is no other distinction between them
+			if (element_eq(dict_read_node(types, edge_iso), inheritance_link)):
+				// It is an inheritance edge, so follow it to its destination
+				destination_iso = read_edge_dst(edge_iso)
+				// Found a new superclass to test
+				if (is_nominal_subtype(superclass, destination_iso, types, inheritance_link)):
+					return True
+		i_iso = integer_addition(i_iso, 1)
+	
+	// No link seems to have been found, so it is False
+	return False
+
+Boolean function is_structural_instance(model_isi : Element, instance_isi : Element, type_isi : Element):
+	return is_structural_subtype(dict_read_node(dict_read(model_isi, "type_mapping"), instance_isi), type_isi)
+	
+Boolean function is_structural_subtype(subtype_isi : Element, supertype_isi : Element):
+	// Determine whether it is just the exact type or not
+	if (element_eq(subtype_isi, supertype_isi)):
+		return True
+
+	// Find all links that are required (name and type) from the specified type
+	Element required_keys_isi
+	required_keys_isi = dict_keys(supertype_isi)
+	Integer required_keys_len_isi
+	required_keys_len_isi = dict_len(required_keys_isi)
+
+	String key_isi
+	Element equivalent_isi
+	Integer i_isi
+	i_isi = 0
+
+	// Go over all keys that we require
+	while (integer_lt(i_isi, required_keys_len_isi)):
+		key_isi = set_pop(required_keys_isi)
+		// Check whether they exist in the instance
+		if (dict_in(subtype_isi, key_isi)):
+			// Normally, we should still check whether they don't violate the constraints imposed on the class (i.e., are actually present)
+			// For now, we ignore this and simply require that it is always there in the metamodel (not necessarily in the instance)
+			// TODO
+
+			// Still check whether the types match
+			if (bool_not(is_structural_subtype(dict_read(subtype_isi, key_isi), dict_read(supertype_isi, key_isi)))):
+				return False
+
+			// All clear, so pass on to the next attribute
+			i_isi = integer_addition(i_isi, 1)
+		else:
+			return False
+
+	// No violations found, so OK
+	return True
+
+String function conformance_scd(model : Element):
+	// Initialization
+	Element work_conf
+	Element model_src
+	Element metamodel_src
+	Element model_dst
+	Element metamodel_dst
+	Element models
+	Element metamodels
+	models = set_copy(dict_read(model, "model"))
+
+	Element typing
+	typing = dict_read(model, "type_mapping")
+	metamodels = set_copy(dict_read(dict_read(model, "metamodel"), "model"))
+	Element inheritance
+	inheritance = dict_read(dict_read(model, "metamodel"), "inheritance")
+	Element metamodel_typing
+	metamodel_typing = dict_read(dict_read(model, "metamodel"), "type_mapping")
+
+	// Iterate over all model elements and check if they are typed (in "typing") and their type is in the metamodel
+	while (integer_gt(dict_len(models), 0)):
+		work_conf = set_pop(models)
+		// Basic check: does the element have a type
+		if (bool_not(dict_in_node(typing, work_conf))):
+			return string_join("Model has no type specified: ", getName(model, work_conf))
+
+		// Basic check: is the type of the element part of the metamodel
+		if (bool_not(set_in_node(metamodels, dict_read_node(typing, work_conf)))):
+			return string_join("Type of element not in specified metamodel: ", getName(model, work_conf))
+
+		// Basic check: type of the value agrees with the actual type
+		// this is always checked, as it falls back to a sane default for non-values
+		if (bool_not(type_eq(dict_read_node(typing, work_conf), typeof(work_conf)))):
+			return string_join("Primitive type does not agree with actual type: ", getName(model, work_conf))
+
+		// For edges only: check whether the source is typed according to the metamodel
+		if (is_edge(work_conf)):
+			model_src = read_edge_src(work_conf)
+			metamodel_src = read_edge_src(dict_read_node(typing, work_conf))
+			if (bool_not(is_nominal_instance(model, model_src, metamodel_src))):
+				return string_join("Source of model edge not typed by source of type: ", getName(model, work_conf))
+
+		// For edges only: check whether the destination is typed according to the metamodel
+		if (is_edge(work_conf)):
+			model_dst = read_edge_dst(work_conf)
+			metamodel_dst = read_edge_dst(dict_read_node(typing, work_conf))
+			if (bool_not(is_nominal_instance(model, model_dst, metamodel_dst))):
+				return string_join("Destination of model edge not typed by destination of type: ", getName(model, work_conf))
+
+	// Structure seems fine, now do static semantics
+	if (dict_in(dict_read(model, "metamodel"), "constraints")):
+		Element constraint_function
+		constraint_function = dict_read(dict_read(model, "metamodel"), "constraints")
+		return constraint_function(model)
+	else:
+		return "OK"
+
+Element function retype(model_rt : Element, metamodel_rt : Element, inheritance_rt : Element, mapping_rt : Element):
+	if (dict_in(model_rt, "type_mapping")):
+		// Remove previous type mappings
+		dict_delete(model_rt, "type_mapping")
+	if (dict_in(model_rt, "metamodel")):
+		// Remove the previous metamodel too, as this might change too
+		dict_delete(model_rt, "metamodel")
+	if (dict_in(model_rt, "inheritance")):
+		// Remove the inheritance link too, as, yet again, this can vary
+		dict_delete(model_rt, "inheritance")
+	
+	// Start the new configuration of the metamodel and inheritance link, as well as set the new mapping relation
+	dict_add(model_rt, "metamodel", metamodel_rt)
+	dict_add(model_rt, "inheritance", inheritance_rt)
+	dict_add(model_rt, "type_mapping", mapping_rt)
+
+	return model_rt
+
+Element function add_to_model(model_atm : Element, name_atm : String, element_atm : Element):
+	if (string_eq(name_atm, "")):
+		// No name desired
+		dict_add(dict_read(model_atm, "model"), string_join("__", cast_id2s(element_atm)), element_atm)
+	else:
+		dict_add(dict_read(model_atm, "model"), name_atm, element_atm)
+	return element_atm
+
+Element function instantiate_bottom_node(model_bn : Element, name_bn : String):
+	Element new_element_bn
+	new_element_bn = create_node()
+	return add_to_model(model_bn, name_bn, new_element_bn)
+
+Element function instantiate_bottom_value(model_bv : Element, name_bv : String, value_bv : Element):
+	Element new_element_bv
+	new_element_bv = create_value(value_bv)
+	return add_to_model(model_bv, name_bv, new_element_bv)
+
+Element function instantiate_bottom_edge(model_be : Element, name_be : String, source_be : Element, target_be : Element):
+	Element new_element_be
+	new_element_be = create_edge(source_be, target_be)
+	return add_to_model(model_be, name_be, new_element_be)
+
+Element function set_model_constraints(model_con : Element, func_con : Element):
+	if (dict_in(model_con, "constraints")):
+		dict_delete(model_con, "constraints")
+	dict_add(model_con, "constraints", func_con)
+	return model_con
+
+Element function instantiate_model_lib(model_mo : Element, type_mo : Element, name_mo : String, optionals : Element, attribute_types : Element, attribute_instances : Element):
+	Element new_element_mo
+	if (is_edge(type_mo)):
+		// Create a new edge from "optionals[0]" to "optionals[1]"
+		new_element_mo = instantiate_bottom_edge(model_mo, name_mo, list_read(optionals, 0), list_read(optionals, 1))
+	else:
+		if (type_eq(typeof(type_mo), Type)):
+			new_element_mo = instantiate_bottom_value(model_mo, name_mo, list_read(optionals, 0))
+		else:
+			new_element_mo = instantiate_bottom_node(model_mo, name_mo)
+
+	// Add it to the type mapping
+	dict_add(dict_read(model_mo, "type_mapping"), new_element_mo, type_mo)
+
+	// Add all attribute types at this level
+	Integer counter_mo
+	Integer max_mo
+	Element keys_mo
+	keys_mo = dict_keys(attribute_types)
+	counter_mo = 0
+	max_mo = list_len(keys_mo)
+
+	Element attr_name_mo
+	Element attr_type_mo
+	Element created_attr_mo
+	Element created_edge_mo
+	Element metamodel_mo
+	metamodel_mo = dict_read(dict_read(model_mo, "metamodel"), "model")
+
+	// For all new attributes
+	while (integer_lt(counter_mo, max_mo)):
+		attr_name_mo = set_pop(keys_mo)
+		attr_type_mo = dict_read(attribute_types, attr_name_mo)
+
+		created_attr_mo = create_edge(new_element_mo, attr_type_mo)
+		created_edge_mo = create_edge(created_attr_mo, attr_name_mo)
+		
+		// Add it to the model
+		dict_add(dict_read(model_mo, "model"), string_join("__", cast_id2s(attr_name_mo)), attr_name_mo)
+		dict_add(dict_read(model_mo, "model"), string_join("__", cast_id2s(attr_type_mo)), attr_type_mo)
+		dict_add(dict_read(model_mo, "model"), string_join("__", cast_id2s(created_attr_mo)), created_attr_mo)
+		dict_add(dict_read(model_mo, "model"), string_join("__", cast_id2s(created_edge_mo)), created_edge_mo)
+
+		// And add the typing
+		dict_add(dict_read(model_mo, "type_mapping"), attr_name_mo, dict_read(metamodel_mo, "__String"))
+		dict_add(dict_read(model_mo, "type_mapping"), attr_type_mo, dict_read(metamodel_mo, "Type"))
+		dict_add(dict_read(model_mo, "type_mapping"), created_attr_mo, dict_read(metamodel_mo, "Attribute"))
+		dict_add(dict_read(model_mo, "type_mapping"), created_edge_mo, dict_read(metamodel_mo, "__Name"))
+
+		// Increase while loop counter
+		counter_mo = integer_addition(counter_mo, 1)
+
+	// Similarly for instantiated attributes
+	counter_mo = 0
+	keys_mo = dict_keys(attribute_instances)
+	max_mo = list_len(keys_mo)
+	Element attr_definer_class_mo
+	Element attr_type_edge_mo
+	Element attr_value_mo
+	Element attr_edge_mo
+
+	while (integer_lt(counter_mo, max_mo)):
+		// Look it up
+		attr_name_mo = set_pop(keys_mo)
+		attr_value_mo = dict_read(attribute_instances, attr_name_mo)
+		attr_definer_class_mo = find_attribute(type_mo, attr_name_mo, dict_read(dict_read(model_mo, "metamodel"), "type_mapping"), dict_read(model_mo, "inheritance"))
+		attr_type_mo = dict_read(attr_definer_class_mo, attr_name_mo)
+		attr_type_edge_mo = dict_read_edge(attr_definer_class_mo, attr_name_mo)
+		attr_edge_mo = create_edge(new_element_mo, attr_value_mo)
+
+		// Add to model
+		dict_add(dict_read(model_mo, "model"), string_join("__", cast_id2s(attr_value_mo)), attr_value_mo)
+		dict_add(dict_read(model_mo, "model"), string_join("__", cast_id2s(attr_edge_mo)), attr_edge_mo)
+
+		// Type the new elements
+		dict_add(dict_read(model_mo, "type_mapping"), attr_value_mo, attr_type_mo)
+		dict_add(dict_read(model_mo, "type_mapping"), attr_edge_mo, attr_type_edge_mo)
+
+		counter_mo = integer_addition(counter_mo, 1)
+
+	return new_element_mo
+
+Element function instantiate_new_model(metamodel_inm : Element, inheritance_inm : Element):
+	Element model_inm
+	model_inm = create_node()
+	dict_add(model_inm, "model", create_node())
+	dict_add(model_inm, "type_mapping", create_node())
+	dict_add(model_inm, "metamodel", metamodel_inm)
+	dict_add(model_inm, "inheritance", inheritance_inm)
+	return model_inm
+
+Element function generate_bottom_type_mapping(model_tm : Element):
+	Element mm_tm
+	mm_tm = dict_read(dict_read(model_tm, "metamodel"), "model")
+	dict_delete(model_tm, "type_mapping")
+	Element tm_tm
+	tm_tm = create_node()
+	dict_add(model_tm, "type_mapping", tm_tm)
+	
+	// Iterate over every element
+	Element elem_keys_tm
+	Element elem_tm
+	elem_keys_tm = dict_keys(dict_read(model_tm, "model"))
+	while (integer_lt(0, read_nr_out(elem_keys_tm))):
+		elem_tm = dict_read(dict_read(model_tm, "model"), set_pop(elem_keys_tm))
+		if (is_edge(elem_tm)):
+			dict_add(tm_tm, elem_tm, dict_read(mm_tm, "Edge"))
+		else:
+			if (string_neq(cast_v2s(elem_tm), "None")):
+				dict_add(tm_tm, elem_tm, dict_read(mm_tm, cast_v2s(typeof(elem_tm))))
+			else:
+				dict_add(tm_tm, elem_tm, dict_read(mm_tm, "Node"))
+
+	return model_tm

+ 430 - 0
bootstrap/constructors.alc

@@ -0,0 +1,430 @@
+include "primitives.alh"
+include "conformance_scd.alh"
+include "library.alh"
+include "io.alh"
+
+Element while_stack = ?
+
+Element function construct_top():
+	Element elem2
+	elem2 = input()
+	if (string_eq(elem2, "global")):
+		return construct_top_global()
+	elif (string_eq(elem2, "funcdef")):
+		return construct_top_funcdef()
+	else:
+		log(string_join("ERROR: did not understand command ", cast_e2s(elem2)))
+
+Element function construct_top_global():
+	Element this_element_tg
+	String declared_element_tg
+	String op_tg
+
+	this_element_tg = create_value(!global)
+	declared_element_tg = input()
+	dict_add(this_element_tg, "var", declared_element_tg)
+
+	// Defines
+	Element assign_tg
+	Element resolve_tg
+	Element value_tg
+	assign_tg = create_value(!assign)
+	dict_add(this_element_tg, "next", assign_tg)
+	resolve_tg = create_value(!resolve)
+	dict_add(assign_tg, "var", resolve_tg)
+	dict_add(resolve_tg, "var", declared_element_tg)
+	op_tg = input()
+	value_tg = create_value(!constant)
+	if (string_eq(op_tg, "deref")):
+		dict_add(value_tg, "node", import_node(input()))
+	elif (string_eq(op_tg, "empty")):
+		dict_add(value_tg, "node", create_node())
+	elif (string_eq(op_tg, "const")):
+		dict_add(value_tg, "node", input())
+	dict_add(assign_tg, "value", value_tg)
+
+	if (input()):
+		dict_add(assign_tg, "next", construct_top())
+	return this_element_tg
+
+Element function construct_top_funcdef():
+	Element funcdef_assign_top
+	Element funcdef_resolve_top
+	Element funcdef_constant_top
+	Element funcdef_formal_top
+	Element funcdef_func_top
+	Element funcdef_params_top
+	Element funcdef_global_top
+
+	funcdef_global_top = create_value(!global)
+	funcdef_assign_top = create_value(!assign)
+	funcdef_resolve_top = create_value(!resolve)
+	funcdef_constant_top = create_value(!constant)
+	funcdef_formal_top = input()
+	funcdef_func_top = create_node()
+	funcdef_params_top = create_node()
+	dict_add(funcdef_global_top, "var", funcdef_formal_top)
+	dict_add(funcdef_global_top, "next", funcdef_assign_top)
+	dict_add(funcdef_assign_top, "var", funcdef_resolve_top)
+	dict_add(funcdef_assign_top, "value", funcdef_constant_top)
+	dict_add(funcdef_resolve_top, "var", funcdef_formal_top)
+	dict_add(funcdef_constant_top, "node", funcdef_func_top)
+	dict_add(funcdef_func_top, "params", funcdef_params_top)
+
+	Integer funcdef_nrParams_top
+	funcdef_nrParams_top = input()
+	Integer funcdef_counter_top
+	funcdef_counter_top = 0
+	Element funcdef_param_top
+
+	String arg_names_decl_top
+	arg_names_decl_top = "abcdefghijklmnopqrstuvwxyz"
+
+	while (integer_lt(funcdef_counter_top, funcdef_nrParams_top)):
+		funcdef_param_top = create_node()
+		dict_add(funcdef_params_top, string_get(arg_names_decl_top, funcdef_counter_top), funcdef_param_top)
+		output(funcdef_param_top)
+		// Output each parameter in turn
+		funcdef_counter_top = integer_addition(funcdef_counter_top, 1)
+
+	// Now add the body
+	dict_add(funcdef_func_top, "body", construct_unknown())
+
+	if (input()):
+		dict_add(funcdef_assign_top, "next", construct_top())
+
+	return funcdef_global_top
+
+Element function construct_unknown():
+	String elem
+	Element new_model
+	Element new_model_model
+	elem = input()
+
+	if (string_eq(elem, "if")):
+		return construct_if()
+	elif (string_eq(elem, "while")):
+		return construct_while()
+	elif (string_eq(elem, "access")):
+		return construct_access()
+	elif (string_eq(elem, "resolve")):
+		return construct_resolve()
+	elif (string_eq(elem, "assign")):
+		return construct_assign()
+	elif (string_eq(elem, "call")):
+		return construct_call()
+	elif (string_eq(elem, "return")):
+		return construct_return()
+	elif (string_eq(elem, "const")):
+		return construct_const()
+	elif (string_eq(elem, "declare")):
+		return construct_declare()
+	elif (string_eq(elem, "global")):
+		return construct_global()
+	elif (string_eq(elem, "funcdef")):
+		return construct_funcdef()
+	elif (string_eq(elem, "output")):
+		return construct_output()
+	elif (string_eq(elem, "input")):
+		return construct_input()
+	elif (string_eq(elem, "deref")):
+		return construct_deref()
+	elif (string_eq(elem, "break")):
+		return construct_break()
+	elif (string_eq(elem, "continue")):
+		return construct_continue()
+	elif (string_eq(elem, "tag")):
+		Element tmp_constructed
+		tmp_constructed = construct_unknown()
+		output(tmp_constructed)
+		return tmp_constructed
+	elif (string_eq(elem, "instantiate_bottom")):
+		new_model = create_node()
+		dict_add(new_model, "model", create_node())
+		instantiate_bottom(new_model)
+		output(new_model)
+		return construct_unknown()
+	elif (string_eq(elem, "instantiate_model")):
+		new_model = instantiate_new_model(input(), dict_read(dict_read(input(), "model"), input()))
+		instantiate_model(new_model)
+		output(new_model)
+		return construct_unknown()
+	elif (string_eq(elem, "retype_model")):
+		retype_model(input())
+		return construct_unknown()
+	else:
+		log(string_join("ERROR: did not understand command ", cast_e2s(elem)))
+
+Element function construct_if():
+	Element this_element_1
+	this_element_1 = create_value(!if)
+	dict_add(this_element_1, "cond", construct_unknown())
+	dict_add(this_element_1, "then", construct_unknown())
+	if (input()):
+		dict_add(this_element_1, "else", construct_unknown())
+	if (input()):
+		dict_add(this_element_1, "next", construct_unknown())
+	return this_element_1
+
+Element function construct_while():
+	Element this_element_2
+	this_element_2 = create_value(!while)
+	dict_add(this_element_2, "cond", construct_unknown())
+
+	list_append(while_stack, this_element_2)
+	dict_add(this_element_2, "body", construct_unknown())
+	list_delete(while_stack, integer_subtraction(list_len(while_stack), 1))
+
+	if (input()):
+		dict_add(this_element_2, "next", construct_unknown())
+	return this_element_2
+
+Element function construct_access():
+	Element this_element_3
+	this_element_3 = create_value(!access)
+	dict_add(this_element_3, "var", construct_unknown())
+	return this_element_3
+
+Element function construct_resolve():
+	Element this_element_4
+	this_element_4 = create_value(!resolve)
+	dict_add(this_element_4, "var", input())
+	return this_element_4
+
+Element function construct_assign():
+	Element this_element_5
+	this_element_5 = create_value(!assign)
+	dict_add(this_element_5, "var", construct_unknown())
+	dict_add(this_element_5, "value", construct_unknown())
+	if (input()):
+		dict_add(this_element_5, "next", construct_unknown())
+	return this_element_5
+
+Element function construct_call():
+	Element this_element_6
+	this_element_6 = create_value(!call)
+	dict_add(this_element_6, "func", construct_unknown())
+
+	Integer nrParams
+	nrParams = input()
+	Integer counter
+	counter = 0
+
+	Element param
+	Element prev_param
+	String arg_names_call
+	arg_names_call = "abcdefghijklmnopqrstuvwxyz"
+
+	while (integer_lt(counter, nrParams)):
+		param = create_node()
+
+		dict_add(param, "name", string_get(arg_names_call, counter))
+		dict_add(param, "value", construct_unknown())
+
+		if (integer_eq(counter, 0)):
+			dict_add(this_element_6, "params", param)
+		else:
+			dict_add(prev_param, "next_param", param)
+		prev_param = param
+
+		counter = integer_addition(counter, 1)
+
+	if (integer_gt(nrParams, 0)):
+		dict_add(this_element_6, "last_param", prev_param)
+
+	if (input()):
+		dict_add(this_element_6, "next", construct_unknown())
+	return this_element_6
+
+Element function construct_return():
+	Element this_element_7
+	this_element_7 = create_value(!return)
+	if (input()):
+		dict_add(this_element_7, "value", construct_unknown())
+	return this_element_7
+
+Element function construct_const():
+	Element this_element_8
+	this_element_8 = create_value(!constant)
+	dict_add(this_element_8, "node", input())
+	return this_element_8
+
+Element function construct_declare():
+	Element this_element_9
+	Element declared_element_1
+	this_element_9 = create_value(!declare)
+	declared_element_1 = create_node()
+	dict_add(this_element_9, "var", declared_element_1)
+	output(declared_element_1)
+	if (input()):
+		dict_add(this_element_9, "next", construct_unknown())
+	return this_element_9
+
+// TODO remove global keyword
+Element function construct_global():
+	Element this_element_10
+	String declared_element_2
+	this_element_10 = create_value(!global)
+	declared_element_2 = input()
+	dict_add(this_element_10, "var", declared_element_2)
+	if (input()):
+		dict_add(this_element_10, "next", construct_unknown())
+	return this_element_10
+
+Element function construct_input():
+	Element this_element_11
+	this_element_11 = create_value(!input)
+	return this_element_11
+
+Element function construct_output():
+	Element this_element_12
+	this_element_12 = create_value(!output)
+	dict_add(this_element_12, "value", construct_unknown())
+	if (input()):
+		dict_add(this_element_12, "next", construct_unknown())
+	return this_element_12
+
+Element function construct_deref():
+	Element this_element_13
+	this_element_13 = create_value(!constant)
+	dict_add(this_element_13, "node", import_node(input()))
+	return this_element_13
+
+Element function construct_funcdef():
+	Element funcdef_assign
+	Element funcdef_resolve
+	Element funcdef_constant
+	Element funcdef_formal
+	Element funcdef_func
+	Element funcdef_params
+
+	funcdef_assign = create_value(!assign)
+	funcdef_resolve = create_value(!resolve)
+	funcdef_constant = create_value(!constant)
+	funcdef_formal = input()
+	funcdef_func = create_node()
+	funcdef_params = create_node()
+	dict_add(funcdef_assign, "var", funcdef_resolve)
+	dict_add(funcdef_assign, "value", funcdef_constant)
+	dict_add(funcdef_resolve, "var", funcdef_formal)
+	dict_add(funcdef_constant, "node", funcdef_func)
+	dict_add(funcdef_func, "params", funcdef_params)
+
+	Integer funcdef_nrParams
+	funcdef_nrParams = input()
+	Integer funcdef_counter
+	funcdef_counter = 0
+	Element funcdef_param
+
+	String arg_names_decl
+	arg_names_decl = "abcdefghijklmnopqrstuvwxyz"
+
+	while (integer_lt(funcdef_counter, funcdef_nrParams)):
+		funcdef_param = create_node()
+		dict_add(funcdef_params, string_get(arg_names_decl, funcdef_counter), funcdef_param)
+		output(funcdef_param)
+		// Output each parameter in turn
+		funcdef_counter = integer_addition(funcdef_counter, 1)
+
+	// Now add the body
+	dict_add(funcdef_func, "body", construct_unknown())
+
+	if (input()):
+		dict_add(funcdef_assign, "next", construct_unknown())
+
+	return funcdef_assign
+
+Element function construct_break():
+	Element this_element_15
+	this_element_15 = create_value(!break)
+	dict_add(this_element_15, "while", dict_read(while_stack, integer_subtraction(list_len(while_stack), 1)))
+	return this_element_15
+
+Element function construct_continue():
+	Element this_element_16
+	this_element_16 = create_value(!continue)
+	dict_add(this_element_16, "while", dict_read(while_stack, integer_subtraction(list_len(while_stack), 1)))
+	return this_element_16
+
+Element function instantiate_bottom(model_18 : Element):
+	Element this_element_18
+	Element bottom_type
+	bottom_type = input()
+	String element_name_18
+	element_name_18 = input()
+
+	// Find out which kind of element we want to create
+	if (string_eq(bottom_type, "node")):
+		instantiate_bottom_node(model_18, element_name_18)
+	elif (string_eq(bottom_type, "value")):
+		instantiate_bottom_value(model_18, element_name_18, input())
+	elif (string_eq(bottom_type, "edge")):
+		instantiate_bottom_edge(model_18, element_name_18, dict_read(dict_read(model_18, "model"), input()), dict_read(dict_read(model_18, "model"), input()))
+
+	// If there is more to come, we also add these elements
+	if (input()):
+		return instantiate_bottom(model_18)
+	else:
+		return model_18
+
+Element function instantiate_model(model_19 : Element):
+	Element type_19
+	type_19 = dict_read(dict_read(dict_read(model_19, "metamodel"), "model"), input())
+
+	Element name_19
+	name_19 = input()
+
+	Element params_19
+	params_19 = create_node()
+	if (is_edge(type_19)):
+		list_append(params_19, dict_read(dict_read(model_19, "model"), input()))
+		list_append(params_19, dict_read(dict_read(model_19, "model"), input()))
+	elif (type_eq(typeof(type_19), Type)):
+		list_append(params_19, input())
+
+	Element attribute_types_19
+	attribute_types_19 = create_node()
+	while (input()):
+		dict_add(attribute_types_19, input(), input())
+
+	Element attribute_instances_19
+	attribute_instances_19 = create_node()
+	while (input()):
+		dict_add(attribute_instances_19, input(), input())
+
+	instantiate_model_lib(model_19, type_19, name_19, params_19, attribute_types_19, attribute_instances_19)
+
+	if (input()):
+		instantiate_model(model_19)
+	
+	return 1
+
+Element function retype_model(model_20 : Element):
+	Element metamodel_20
+	metamodel_20 = input()
+
+	Element inheritance_20
+	inheritance_20 = dict_read(dict_read(input(), "model"), input())
+
+	Element mapping_20
+	mapping_20 = create_node()
+	while (input()):
+		dict_add(mapping_20, dict_read(dict_read(model_20, "model"), input()), dict_read(dict_read(metamodel_20, "model"), input()))
+
+	return retype(model_20, metamodel_20, inheritance_20, mapping_20)
+
+Element function find_attribute(source_21 : Element, attr_name_21 : Element, types_21 : Element, inheritance_link_21 : Element):
+	if (dict_in(source_21, attr_name_21)):
+		return source_21
+	else:
+		Integer counter_21
+		Integer i
+		Element edge
+		counter_21 = read_nr_out(source_21)
+		i = 0
+		while (integer_lt(i, counter_21)):
+			edge = read_out(source_21, i)
+			if (element_eq(dict_read_node(types_21, edge), inheritance_link_21)):
+				return find_attribute(read_edge_dst(edge), attr_name_21, types_21, inheritance_link_21)
+			i = integer_addition(i, 1)
+		// No return at the moment, as this crashes the MvK

+ 37 - 0
bootstrap/library.alc

@@ -0,0 +1,37 @@
+include "primitives.alh"
+
+Element function export_node(model_name_ex : String, model_reference : Element):
+	Element splitted_ex
+	splitted_ex = string_split(model_name_ex, "/")
+	Integer length_ex
+	length_ex = integer_subtraction(list_len(splitted_ex), 1)
+	Integer counter_i_ex
+	counter_i_ex = 0
+	Element current_ex
+	current_ex = dict_read(read_root(), "__hierarchy")
+	while(integer_lt(counter_i_ex, length_ex)):
+		if (bool_not(dict_in(current_ex, list_read(splitted_ex, counter_i_ex)))):
+			// Create it first
+			dict_add(current_ex, list_read(splitted_ex, counter_i_ex), create_node())
+		current_ex = dict_read(current_ex, list_read(splitted_ex, counter_i_ex))
+		counter_i_ex = integer_addition(counter_i_ex, 1)
+	
+	// current now contains the place where we should add the element
+	dict_add(current_ex, list_read(splitted_ex, length_ex), model_reference)
+
+	return model_reference
+
+Element function import_node(model_name_im : String):
+	Element splitted_im
+	splitted_im = string_split(model_name_im, "/")
+	Integer length_im
+	length_im = list_len(splitted_im)
+	Integer counter_i_im
+	counter_i_im = 0
+	Element current_im
+	current_im = dict_read(read_root(), "__hierarchy")
+	while (integer_lt(counter_i_im, length_im)):
+		current_im = dict_read(current_im, list_read(splitted_im, counter_i_im))
+		counter_i_im = integer_addition(counter_i_im, 1)
+
+	return current_im

+ 195 - 0
bootstrap/object_operations.alc

@@ -0,0 +1,195 @@
+include "primitives.alh"
+include "conformance_scd.alh"
+include "constructors.alh"
+
+Element function allInstances(model_ai : Element, type_ai : Element):
+	Element type_mapping_ai
+	Element result_ai
+
+	type_mapping_ai = dict_read(model_ai, "type_mapping")
+	result_ai = create_node()
+
+	Integer counter_ai
+	counter_ai = 0
+
+	Integer length_ai
+	length_ai = read_nr_out(type_mapping_ai)
+
+	Element edge_ai
+	while (integer_lt(counter_ai, length_ai)):
+		edge_ai = read_out(type_mapping_ai, counter_ai)
+		if (element_eq(read_edge_dst(edge_ai), type_ai)):
+			// Found an element of the specified type
+			set_add(result_ai, read_edge_dst(read_out(edge_ai, 0)))
+		counter_ai = integer_addition(counter_ai, 1)
+	
+	return result_ai
+
+Element function allOutgoingAssociationInstances(model_aoai : Element, source_aoai : Element, assoc_aoai : Element):
+	// Read out all outgoing edges of the model and select those that are typed by the specified association
+	// TODO for some reason this crashes if allInstances is used!
+	Integer length_aoai
+	length_aoai = read_nr_out(source_aoai)
+
+	Integer counter_aoai
+	counter_aoai = 0
+
+	Element result_aoai
+	result_aoai = create_node()
+
+	Element edge_aoai
+	while (integer_lt(counter_aoai, length_aoai)):
+		edge_aoai = read_out(source_aoai, counter_aoai)
+		if (element_eq(dict_read_node(dict_read(model_aoai, "type_mapping"), edge_aoai), assoc_aoai)):
+			set_add(result_aoai, edge_aoai)
+		counter_aoai = integer_addition(counter_aoai, 1)
+	return result_aoai
+
+Element function allIncomingAssociationInstances(model_aiai : Element, source_aiai : Element, assoc_aiai : Element):
+	// Read out all outgoing edges of the model and select those that are typed by the specified association
+	Element result_aiai
+	result_aiai = create_node()
+	Element allinsts_aiai
+	allinsts_aiai = allInstances(model_aiai, assoc_aiai)
+
+	Element understudy_aiai
+	while (integer_lt(0, read_nr_out(allinsts_aiai))):
+		understudy_aiai = set_pop(allinsts_aiai)
+		if (element_eq(read_edge_dst(understudy_aiai), source_aiai)):
+			set_add(result_aiai, understudy_aiai)
+	return result_aiai
+
+Element function readElementByName(model_rebn : Element, name_rebn : String):
+	return dict_read(dict_read(model_rebn, "model"), name_rebn)
+
+Element function findAttribute(source_fa : Element, attr_name_fa : Element, types_fa : Element, inheritance_link_fa : Element):
+	if (dict_in(source_fa, attr_name_fa)):
+		return dict_read_edge(source_fa, attr_name_fa)
+	else:
+		Integer counter_fa
+		Integer i_fa
+		Element edge_fa
+		counter_fa = read_nr_out(source_fa)
+		i_fa = 0
+		while (integer_lt(i_fa, counter_fa)):
+			edge_fa = read_out(source_fa, i_fa)
+			if (element_eq(dict_read_node(types_fa, edge_fa), inheritance_link_fa)):
+				return find_attribute(read_edge_dst(edge_fa), attr_name_fa, types_fa, inheritance_link_fa)
+			i_fa = integer_addition(i_fa, 1)
+		// No return at the moment, as this crashes the MvK
+		log("ERROR: could not find attribute")
+
+Element function readAttribute(model_ra : Element, source_ra : Element, attr_name_ra : String):
+	// Read out the edge we are talking about
+	Element edge_ra
+	edge_ra = findAttribute(dict_read_node(dict_read(model_ra, "type_mapping"), source_ra), attr_name_ra, dict_read(model_ra, "type_mapping"), dict_read(model_ra, "inheritance"))
+
+	return read_edge_dst(set_pop(allOutgoingAssociationInstances(model_ra, source_ra, edge_ra)))
+
+Element function setAttribute(model_sa : Element, source_sa : Element, attr_name_sa : String, value_sa : Element):
+	// Read out which edge we are talking about
+	Element edge_sa
+	edge_sa = deleteAttribute(model_sa, source_sa, attr_name_sa)
+
+	// Now make the element
+	Element created_edge_sa
+	created_edge_sa = create_edge(source_sa, value_sa)
+	dict_add(dict_read(model_sa, "type_mapping"), created_edge_sa, edge_sa)
+	dict_add(dict_read(model_sa, "type_mapping"), value_sa, read_edge_dst(edge_sa))
+	add_to_model(model_sa, "", value_sa)
+	add_to_model(model_sa, "", created_edge_sa)
+
+	return True
+
+Element function deleteAttribute(model_da : Element, source_da : Element, attr_name_da : Element):
+	Element edge_da
+	edge_da = findAttribute(dict_read_node(dict_read(model_da, "type_mapping"), source_da), attr_name_da, dict_read(model_da, "type_mapping"), dict_read(model_da, "inheritance"))
+
+	Element found_elements_da
+	found_elements_da = allOutgoingAssociationInstances(model_da, source_da, edge_da)
+
+	Element rm_element_da
+	if (integer_gt(list_len(found_elements_da), 0)):
+		rm_element_da = read_edge_dst(set_pop(found_elements_da))
+		dict_delete(dict_read(model_da, "type_mapping"), rm_element_da)
+		delete_element(rm_element_da)
+
+	return edge_da
+
+Element function getAttributeList(model_gali : Element, mm_gali : Element):
+	Element result_gali
+	result_gali = create_node()
+	// Get all outgoing "dictionary" links
+	Element set_gali_own
+	set_gali_own = dict_keys(mm_gali)
+
+	// Filter them
+	Element e_gali
+	while (integer_lt(0, read_nr_out(set_gali_own))):
+		e_gali = set_pop(set_gali_own)
+		if (type_eq(typeof(e_gali), String)):
+			if (type_eq(typeof(dict_read(mm_gali, e_gali)), Type)):
+				// This is a primitive type, so add to the list
+				dict_add(result_gali, e_gali, dict_read(mm_gali, e_gali))
+
+	// And go up to the possible supertypes
+	Element found_elements_gali
+	found_elements_gali = allOutgoingAssociationInstances(model_gali, mm_gali, dict_read(model_gali, "inheritance"))
+	Element dict_gali_super
+	Integer i_gali
+	Integer max_gali
+	Element set_gali_super
+	Element found_key_gali
+	while (integer_lt(0, read_nr_out(found_elements_gali))):
+		// Now find the destination of these associations, which are the superclasses of this model
+		dict_gali_super = getAttributeList(model_gali, read_edge_dst(set_pop(found_elements_gali)))
+		set_gali_super = dict_keys(dict_gali_super)
+		// Merge the two
+		while (integer_lt(0, read_nr_out(set_gali_super))):
+			found_key_gali = set_pop(set_gali_super)
+			dict_add(result_gali, found_key_gali, dict_read(dict_gali_super, found_key_gali))
+
+	return result_gali
+
+Element function getInstantiatableAttributes(model_gili : Element, element_gili : Element):
+	Element result_gili
+	result_gili = create_node()
+	// Get all outgoing "dictionary" links
+	Element set_gili_own
+	set_gili_own = dict_keys(element_gili)
+
+	// Filter them
+	Element e_gili
+	while (integer_lt(0, read_nr_out(set_gili_own))):
+		e_gili = set_pop(set_gili_own)
+		if (bool_and(type_eq(typeof(e_gili), String), type_eq(typeof(dict_read(element_gili, e_gili)), Type))):
+			// This is a primitive type, so add to the list
+			dict_add(result_gili, e_gili, dict_read(element_gili, e_gili))
+
+	return result_gili
+
+String function getName(m : Element, e : Element):
+	Element element_keys
+	Element s
+	s = dict_read(m, "model")
+	element_keys = dict_keys(s)
+
+	while (integer_lt(0, read_nr_out(element_keys))):
+		Element key
+		key = set_pop(element_keys)
+		if (element_eq(dict_read_node(s, key), e)):
+			return key
+
+	return string_join(string_join("(unknown: ", cast_e2s(e)), " )")
+
+String function reverseNameLookup(s_rnl : Element, e_rnl : Element):
+	Element element_keys_rnl
+	element_keys_rnl = dict_keys(s_rnl)
+
+	while (integer_lt(0, read_nr_out(element_keys_rnl))):
+		Element key_rnl
+		key_rnl = set_pop(element_keys_rnl)
+		if (element_eq(dict_read_node(s_rnl, key_rnl), e_rnl)):
+			return key_rnl
+
+	return string_join(string_join("(unknown: ", cast_e2s(e_rnl)), " )")

+ 114 - 0
bootstrap/primitives.alc

@@ -0,0 +1,114 @@
+Boolean function action_eq(a: Action, b: Action) = ?primitives/action_eq
+Boolean function action_neq(a: Action, b: Action) = ?primitives/action_neq
+Boolean function bool_and(a: Boolean, b: Boolean) = ?primitives/bool_and
+Boolean function bool_or(a: Boolean, b: Boolean) = ?primitives/bool_or
+Boolean function bool_not(a: Boolean) = ?primitives/bool_not
+Boolean function bool_eq(a: Boolean, b: Boolean) = ?primitives/bool_eq
+Boolean function bool_neq(a: Boolean, b: Boolean) = ?primitives/bool_neq
+Element function create_node() = ?primitives/create_node
+Element function create_edge(a: Element, b: Element) = ?primitives/create_edge
+Element function create_value(a: Element)  = ?primitives/create_value
+Boolean function is_edge(a: Element)  = ?primitives/is_edge
+Integer function read_nr_out(a: Element)  = ?primitives/read_nr_out
+Element function read_out(a: Element, b: Integer)  = ?primitives/read_out
+Integer function read_nr_in(a: Element)  = ?primitives/read_nr_in
+Element function read_in(a: Element, b: Integer)  = ?primitives/read_in
+Element function read_edge_src(a: Element)  = ?primitives/read_edge_src
+Element function read_edge_dst(a: Element)  = ?primitives/read_edge_dst
+Boolean function delete_element(a: Element)  = ?primitives/delete_element
+Boolean function element_eq(a: Element, b: Element)  = ?primitives/element_eq
+Boolean function element_neq(a: Element, b: Element)  = ?primitives/element_neq
+Float function cast_i2f(a: Integer) = ?primitives/cast_i2f
+String function cast_i2s(a: Integer)  = ?primitives/cast_i2s
+Boolean function cast_i2b(a: Integer)  = ?primitives/cast_i2b
+Integer function cast_f2i(a: Float)  = ?primitives/cast_f2i
+Boolean function cast_f2b(a: Float)  = ?primitives/cast_f2b
+String function cast_f2s(a: Float)  = ?primitives/cast_f2s
+Integer function cast_s2i(a: String)  = ?primitives/cast_s2i
+Float function cast_s2f(a: String)  = ?primitives/cast_s2f
+Boolean function cast_s2b(a: String)  = ?primitives/cast_s2b
+Integer function cast_b2i(a: Boolean)  = ?primitives/cast_b2i
+Float function cast_b2f(a: Boolean)  = ?primitives/cast_b2f
+String function cast_b2s(a: Boolean)  = ?primitives/cast_b2s
+String function cast_e2s(a: Element)  = ?primitives/cast_e2s
+String function cast_a2s(a: Action)  = ?primitives/cast_a2s
+String function cast_t2s(a: Type)  = ?primitives/cast_t2s
+String function cast_v2s(a: Element)  = ?primitives/cast_v2s
+String function cast_id2s(a: Element)  = ?primitives/cast_id2s
+Element function dict_add(a: Element, b: Element, c: Element) = ?primitives/dict_add
+Element function dict_delete(a: Element, b: Element) = ?primitives/dict_delete
+Element function dict_read(a: Element, b: Element)  = ?primitives/dict_read
+Element function dict_read_edge(a: Element, b: Element)  = ?primitives/dict_read_edge
+Element function dict_read_node(a: Element, b: Element)  = ?primitives/dict_read_node
+Integer function dict_len(a: Element)  = ?primitives/dict_len
+Boolean function dict_in(a: Element, b: Element)  = ?primitives/dict_in
+Boolean function dict_in_node(a: Element, b: Element)  = ?primitives/dict_in_node
+Element function dict_keys(a: Element)  = ?primitives/dict_keys
+Float function float_addition(a: Float, b: Float) = ?primitives/float_addition
+Float function float_subtraction(a: Float, b: Float)  = ?primitives/float_subtraction
+Float function float_multiplication(a: Float, b: Float)  = ?primitives/float_multiplication
+Float function float_division(a: Float, b: Float)  = ?primitives/float_division
+Boolean function float_gt(a: Float, b: Float)  = ?primitives/float_gt
+Boolean function float_gte(a: Float, b: Float)  = ?primitives/float_gte
+Boolean function float_lt(a: Float, b: Float)  = ?primitives/float_lt
+Boolean function float_lte(a: Float, b: Float)  = ?primitives/float_lte
+Boolean function float_eq(a: Float, b: Float)  = ?primitives/float_eq
+Boolean function float_neq(a: Float, b: Float)  = ?primitives/float_neq
+Boolean function float_neg(a: Float) = ?primitives/float_neg
+Integer function integer_addition(a: Integer, b: Integer) = ?primitives/integer_addition
+Integer function integer_subtraction(a: Integer, b: Integer)  = ?primitives/integer_subtraction
+Integer function integer_multiplication(a: Integer, b: Integer)  = ?primitives/integer_multiplication
+Integer function integer_division(a: Integer, b: Integer)  = ?primitives/integer_division
+Boolean function integer_gt(a: Integer, b: Integer)  = ?primitives/integer_gt
+Boolean function integer_gte(a: Integer, b: Integer)  = ?primitives/integer_gte
+Boolean function integer_lt(a: Integer, b: Integer)  = ?primitives/integer_lt
+Boolean function integer_lte(a: Integer, b: Integer)  = ?primitives/integer_lte
+Boolean function integer_eq(a: Integer, b: Integer)  = ?primitives/integer_eq
+Boolean function integer_neq(a: Integer, b: Integer)  = ?primitives/integer_neq
+Boolean function integer_neg(a: Integer) = ?primitives/integer_neg
+Element function list_read(a: Element, b: Integer) = ?primitives/list_read
+Element function list_append(a: Element, b: Element)  = ?primitives/list_append
+Element function list_insert(a: Element, b: Element, c: Integer)  = ?primitives/list_insert
+Element function list_delete(a: Element, b: Integer)  = ?primitives/list_delete
+Integer function list_len(a: Element)  = ?primitives/list_len
+Element function set_add(a: Element, b: Element)  = ?primitives/set_add
+Element function set_pop(a: Element)  = ?primitives/set_pop
+Element function set_remove(a: Element, b: Element)  = ?primitives/set_remove
+Boolean function set_in(a: Element, b: Element)  = ?primitives/set_in
+Element function set_remove_node(a: Element, b: Element)  = ?primitives/set_remove_node
+Element function set_in_node(a: Element, b: Element)  = ?primitives/set_in_node
+String function string_join(a: String, b: String)  = ?primitives/string_join
+String function string_get(a: String, b: Integer)  = ?primitives/string_get
+String function string_substr(a: String, b: Integer, c: Integer)  = ?primitives/string_substr
+Integer function string_len(a: String)  = ?primitives/string_len
+Boolean function string_eq(a: String, b: String)  = ?primitives/string_eq
+Boolean function string_neq(a: String, b: String)  = ?primitives/string_neq
+Element function string_split(a: String, b: String)  = ?primitives/string_split
+Boolean function string_startswith(a: String, b: String)  = ?primitives/string_startswith
+Boolean function type_eq(a: Type, b: Type)  = ?primitives/type_eq
+Boolean function type_neq(a: Type, b: Type)  = ?primitives/type_neq
+Type function typeof(a: Element)  = ?primitives/typeof
+Element function deserialize(a: String)  = ?primitives/deserialize
+Element function log(a: String) = ?primitives/log
+Element function read_root() = ?primitives/read_root
+
+Element function exec(first_instr : Element):
+	// This does very ugly things, so beware!
+	// Basically, we dynamically construct an if True condition with as body the provided instructions
+	//  after the if conditional, we append a return of an empty element, as we need a return at the end
+	//  returns in the code are therefore allowed (and will be the return value), but not necessarily
+	Element n
+	n = create_node()
+	dict_add(n, "params", create_node())
+	Element exec_if
+	exec_if = create_value(!if)
+	Element exec_const_true
+	exec_const_true = create_value(!constant)
+	dict_add(exec_const_true, "node", create_value(True))
+	dict_add(exec_if, "cond", exec_const_true)
+	dict_add(exec_if, "then", first_instr)
+	dict_add(n, "body", exec_if)
+	Element exec_return
+	exec_return = create_value(!return)
+	dict_add(exec_if, "next", exec_return)
+	return n()

+ 11 - 0
compile.sh

@@ -0,0 +1,11 @@
+#!/bin/bash
+set -e
+
+source library.sh
+
+# Leave this here too, as the call might crash early
+curl http://localhost:8001 -d "op=set_input&username=user_manager&element_type=V&value=\"$2\"" -s -S >> /dev/null
+
+f=`realpath $1`
+cd interface/HUTN
+${python} hutn_compiler/compiler.py $f grammars/actionlanguage.g ${4-PO} $2 $3 $f

+ 13 - 0
fix_linux.sh

@@ -0,0 +1,13 @@
+#!/bin/bash
+ln -s ../utils.py kernel/test/functions/utils.py
+ln -s ../utils.py kernel/test/instructions/utils.py
+ln -s ../utils.py kernel/test/primitives/utils.py
+ln -s ../utils.py kernel/test/rules/utils.py
+
+ln -s ../util.py interface/HUTN/test/grammar_action_language/util.py
+ln -s ../util.py interface/HUTN/test/graph_compilation_action_language/util.py
+
+ln -s ../../state/mvs_server/primitives.mvi interface/HUTN/primitives.mvi
+ln -s ../../state/mvs_server/primitives.mvs interface/HUTN/primitives.mvs
+ln -s ../../state/mvs_server/primitives.mvi kernel/test/primitives.mvi
+ln -s ../../state/mvs_server/primitives.mvs kernel/test/initial.mvs

+ 12 - 0
fix_windows.bat

@@ -0,0 +1,12 @@
+copy kernel\test\utils.py kernel\test\functions\utils.py
+copy kernel\test\utils.py kernel\test\instructions\utils.py
+copy kernel\test\utils.py kernel\test\primitives\utils.py
+copy kernel\test\utils.py kernel\test\rules\utils.py
+
+copy interface\HUTN\test\util.py interface\HUTN\test\grammar_action_language\util.py
+copy interface\HUTN\test\util.py interface\HUTN\test\graph_compilation_action_language\util.py
+
+copy state\mvs_server\primitives.mvi interface\HUTN\primitives.mvi
+copy state\mvs_server\primitives.mvs interface\HUTN\primitives.mvs
+copy state\mvs_server\primitives.mvi kernel\test\primitives.mvi
+copy state\mvs_server\primitives.mvs kernel\test\initial.mvs

+ 2 - 0
flush_compiler_caches.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+find . -type f -name '*.pickle' -delete

+ 3 - 0
generate_bootstrap.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+cd bootstrap
+pypy bootstrap.py

+ 198 - 0
hybrid_server/classes/mvkcontroller.xml

@@ -0,0 +1,198 @@
+<class name="MvKController">
+    <relationships>
+        <association name="to_mvi" class="Server" min="1" max="1"/>
+    </relationships>
+    <constructor>
+        <parameter name="params"/>
+        <body>
+            <![CDATA[
+            self.mvs = ModelverseState("../bootstrap/bootstrap.m")
+            self.root = self.mvs.read_root()[0]
+            self.mvk = ModelverseKernel(self.root)
+            self.all_failed = False
+            self.timeout = False
+
+            self.users = set()
+            self.input_queue = defaultdict(list)
+            self.output_queue = defaultdict(list)
+            self.source = None
+
+            self.mvs_operations = {
+                    "CN": self.mvs.create_node,
+                    "CE": self.mvs.create_edge,
+                    "CNV": self.mvs.create_nodevalue,
+                    "CD": self.mvs.create_dict,
+
+                    "RV": self.mvs.read_value,
+                    "RO": self.mvs.read_outgoing,
+                    "RI": self.mvs.read_incoming,
+                    "RE": self.mvs.read_edge,
+                    "RD": self.mvs.read_dict,
+                    "RDN": self.mvs.read_dict_node,
+                    "RDNE": self.mvs.read_dict_node_edge,
+                    "RDE": self.mvs.read_dict_edge,
+                    "RRD": self.mvs.read_reverse_dict,
+                    "RR": self.mvs.read_root,
+                    "RDK": self.mvs.read_dict_keys,
+
+                    "DE": self.mvs.delete_edge,
+                    "DN": self.mvs.delete_node,
+                }
+
+            self.execute_modelverse("", "load_primitives", [])
+            ]]>
+        </body>
+    </constructor>
+
+    <method name="execute_modelverse">
+        <parameter name="username"/>
+        <parameter name="operation"/>
+        <parameter name="params"/>
+        <body>
+            <![CDATA[
+            reply = None
+            commands = []
+            while 1:
+                commands = self.mvk.execute_yields(username, operation, params, reply)
+                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>
+
+    <scxml initial="init_server">
+        <state id="init_server">
+            <onentry>
+                <raise scope="cd" event="create_instance">
+                    <parameter expr="'to_mvi'"/>
+                    <parameter expr="'Server'"/>
+                    <parameter expr="''"/>
+                    <parameter expr="8001"/>
+                </raise>
+            </onentry>
+            <transition event="instance_created" target="../running">
+                <parameter name="instancename"/>
+                <raise scope="cd" event="start_instance">
+                    <parameter expr="instancename"/>
+                </raise>
+            </transition>
+        </state>
+
+        <parallel id="running">
+            <state id="wait_for_requests">
+                <state id="wait">
+                    <transition event="from_mvi" target=".">
+                        <parameter name="source"/>
+                        <parameter name="data"/>
+                        <script>
+                            # No JSON encoding necessary, as it is not complex
+                            try:
+                                if data["op"] == "set_input":
+                                    if "element_type" in data:
+                                        if data["element_type"] == "V":
+                                            value = json.loads(data["value"])
+                                        else:
+                                            value = data["value"]
+                                        args = [data["element_type"], value]
+                                        self.input_queue[data["username"]].append((source, [args]))
+                                    else:
+                                        d = []
+                                        for t, v in json.loads(data["data"]):
+                                            if t == "V":
+                                                v = json.loads(v)
+                                            d.append([t, v])
+                                        self.input_queue[data["username"]].append((source, d))
+                                elif data["op"] == "get_output":
+                                    self.output_queue[data["username"]].append(source)
+                                else:
+                                    print("DROPPING unknown operation: " + str(data["op"]))
+                            except:
+                                print("DROPPING deserialization error")
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="execution">
+                <state id="execution">
+                    <onentry>
+                        <script>
+                            self.timeout = False
+                            self.destination = None
+                            if self.users:
+                                user = self.users.pop()
+
+                                # Check if there are values to input
+                                if self.input_queue[user]:
+                                    source, args = self.input_queue[user].pop(0)
+                                    for args_entry in args:
+                                        self.execute_modelverse(user, "set_input", args_entry)
+
+                                    self.destination = source
+                                    self.value = {"id": 200, "value": "OK"}
+                                    self.all_failed = False
+
+                                # Now process for some steps, or until we are again blocked for input
+                                for x in xrange(200):
+                                    self.execute_modelverse(user, "execute_rule", [])
+
+                                    if not self.mvk.success:
+                                        # Blocking or broken, so quit already to stop wasting CPU
+                                        break
+
+                                    self.all_failed = False
+
+                                # Check that we don't have anything to output yet, otherwise we wait
+                                if self.destination is None:
+                                    # Perform output if there is anything
+                                    if self.output_queue[user]:
+                                        self.execute_modelverse(user, "get_output", [])
+                                        if self.mvk.success:
+                                            self.destination = self.output_queue[user].pop(0)
+                                            self.value = self.mvk.returnvalue
+                                            self.all_failed = False
+                            else:
+                                out = self.mvs.read_outgoing(self.root)[0]
+                                for m in out:
+                                    src, user = self.mvs.read_edge(m)[0]
+                                    outgoing = self.mvs.read_outgoing(m)[0]
+                                    first = self.mvs.read_edge(outgoing[0])[0]
+                                    dest = first[1]
+                                    name = self.mvs.read_value(dest)[0]
+                                    if name.startswith("__"):
+                                        continue
+                                    self.users.add(name)
+                                self.timeout = self.all_failed
+                                self.all_failed = True
+                        </script>
+                    </onentry>
+
+                    <transition cond="self.destination is not None" after="0" target=".">
+                        <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.destination">
+                            <parameter expr="self.value"/>
+                        </raise>
+                    </transition>
+
+                    <transition cond="self.timeout and self.destination is None" after="0.1" target="."/>
+
+                    <transition cond="not self.timeout and self.destination is None" after="0" target="."/>
+                </state>
+            </state>
+
+            <state id="remove_sockets">
+                <state id="remove_sockets">
+                    <transition event="delete_socket" target=".">
+                        <parameter name="socket"/>
+                        <script>
+                            for user in self.output_queue.keys():
+                                self.output_queue[user] = [s for s in self.output_queue[user] if s != socket]
+                        </script>
+                    </transition>
+                </state>
+            </state>
+        </parallel>
+    </scxml>
+</class>

+ 110 - 0
hybrid_server/classes/server.xml

@@ -0,0 +1,110 @@
+<class name="Server">
+    <relationships>
+        <association name="sockets" class="Socket"/>
+        <association name="parent" class="MvKController" min="1" max="1"/>
+    </relationships>
+    <constructor>
+        <parameter name="address"/>
+        <parameter name="port"/>
+        <body>
+            <![CDATA[
+            self.socket = None
+            self.address = address
+            self.port = port
+            ]]>
+        </body>
+    </constructor>
+
+    <scxml initial="main">
+        <parallel id="main">
+            <state id="forward">
+                <state id="forward">
+                    <transition event="HTTP_output" target=".">
+                        <parameter name="association_name"/>
+                        <parameter name="data"/>
+                        <raise event="from_mvi" scope="narrow" target="'parent'">
+                            <parameter expr="association_name"/>
+                            <parameter expr="data"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="server" initial="init">
+                <state id="init">
+                    <onentry>
+                        <raise scope="output" event="create_socket" port="socket_out"/>
+                    </onentry>
+                    <transition port="socket_in" event="created_socket" target="../binding">
+                        <parameter name="socket"/>
+                        <script>
+                            self.socket = socket
+                        </script>
+                    </transition>
+                </state>
+                <state id="binding">
+                    <onentry>
+                        <raise scope="output" event="bind_socket" port="socket_out">
+                            <parameter expr="self.socket"/>
+                            <parameter expr="(self.address, self.port)"/>
+                        </raise>
+                    </onentry>
+                    <transition port="socket_in" event="bound_socket" cond="self.socket == socket" target="../listening">
+                        <parameter name="socket"/>
+                    </transition>
+                </state>
+                <state id="listening">
+                    <onentry>
+                        <raise scope="output" event="listen_socket" port="socket_out">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </onentry>
+                    <transition port="socket_in" event="listened_socket" cond="self.socket == socket" target="../accepting">
+                        <parameter name="socket"/>
+                        <raise scope="output" port="socket_out" event="accept_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </transition>
+                </state>
+                <state id="accepting">
+                    <transition port="socket_in" event="accepted_socket" target=".">
+                        <parameter name="socket"/>
+                        <parameter name="connected_socket"/>
+                        <raise scope="cd" event="create_instance">
+                            <parameter expr="'sockets'" />
+                            <parameter expr="'Socket'" />
+                            <parameter expr="connected_socket" />
+                        </raise>
+                        <raise scope="output" port="socket_out" event="accept_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </transition>
+                    <transition event="instance_created" target=".">
+                        <parameter name="instancename"/>
+                        <raise scope="cd" event="start_instance">
+                            <parameter expr="instancename" />
+                        </raise>
+                        <raise scope="narrow" event="set_association_name" target="instancename">
+                            <parameter expr="instancename"/>
+                        </raise>
+                    </transition>
+                    <transition after="1.0" target="."/>
+                </state>
+            </state>
+
+            <state id="close_socket">
+                <state id="close">
+                    <transition event="close_socket" target=".">
+                        <parameter name="association_name"/>
+                        <raise scope="cd" event="delete_instance">
+                            <parameter expr="association_name"/>
+                        </raise>
+                        <raise scope="broad" event="delete_socket">
+                            <parameter expr="association_name"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+        </parallel>
+    </scxml>
+</class>

+ 154 - 0
hybrid_server/classes/socket.xml

@@ -0,0 +1,154 @@
+<class name="Socket">
+    <relationships>
+        <association name="parent" class="Server" min="1" max="1"/>
+    </relationships>
+
+    <constructor>
+        <parameter name="my_socket"/>
+        <body>
+            <![CDATA[
+            self.socket = my_socket
+            self.received_data = ""
+            self.send_data = ""
+            self.closed = False
+            self.association_name = None
+            ]]>
+        </body>
+    </constructor>
+    <scxml initial="init">
+        <state id="init">
+            <transition event="set_association_name" target="../connected">
+                <parameter name="association_name"/>
+                <script>
+                    self.association_name = association_name
+                </script>
+            </transition>
+        </state>
+        <parallel id="connected">
+            <state id="listening" initial="listen">
+                <state id="listen">
+                    <onentry>
+                        <raise scope="output" port="socket_out" event="recv_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </onentry>
+                    <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) > 0)" target=".">
+                        <parameter name="socket"/>
+                        <parameter name="data"/>
+                        <script>
+                            self.received_data += data
+                        </script>
+                        <raise event="received_data"/>
+                    </transition>
+                    <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) == 0)" target="../closed">
+                        <parameter name="socket"/>
+                        <parameter name="data"/>
+                        <raise event="received_data"/>
+                    </transition>
+                </state>
+                <state id="closed">
+                    <onentry>
+                        <script>
+                            self.closed = True
+                        </script>
+                    </onentry>
+                </state>
+            </state>
+
+            <state id="sending" initial="waiting_for_data">
+                <state id="waiting_for_data">
+                    <transition cond="len(self.send_data) > 0" target="../transferring">
+                        <raise scope="output" port="socket_out" event="send_socket">
+                            <parameter expr="self.socket"/>
+                            <parameter expr="self.send_data"/>
+                        </raise>
+                    </transition>
+                </state>
+                <state id="transferring">
+                    <transition event="sent_socket" port="socket_in" cond="self.socket == socket" target="../waiting_for_data">
+                        <parameter name="socket"/>
+                        <parameter name="sent_bytes"/>
+                        <script>
+                            self.send_data = self.send_data[sent_bytes:]
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="queueing">
+                <state id="queueing">
+                    <transition event="HTTP_input" target=".">
+                        <parameter name="data"/>
+                        <script>
+                            #post_data = "&amp;".join(["%s=%s" % (urllib.quote(k), urllib.quote(v)) for k, v in data.iteritems()])
+                            post_data = "&amp;".join(["%s=%s" % (k, v) for k, v in data.iteritems()])
+                            self.send_data += "HTTP/1.0 200 OK\r\n"
+                            self.send_data += "Content-Length: %s\r\n" % len(post_data)
+                            self.send_data += "Content-Type: %s; charset=UTF-8\r\n" % "text/plain"
+                            self.send_data += "\r\n"
+                            self.send_data += str(post_data)
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="parsing" initial="wait_for_header">
+                <state id="wait_for_header">
+                    <transition cond="'\r\n\r\n' in self.received_data and self.received_data.startswith('POST')" target="../wait_for_payload">
+                        <script>
+                            header, self.received_data = self.received_data.split("\r\n\r\n", 1)
+                            header = header.lower()
+                            if "content-length" in header:
+                                _, after = header.split("content-length:", 1)
+                                after = after.split("\r\n", 1)[0]
+                                after = after.strip()
+                                self.length = int(after)
+                            else:
+                                self.length = float('inf')
+                        </script>
+                    </transition>
+                    <transition cond="self.closed and len(self.received_data) == 0" target="../closing"/>
+                </state>
+                <state id="closing">
+                    <transition after="0.0" target=".">
+                        <raise event="close"/>
+                    </transition>
+                </state>
+                <state id="wait_for_payload">
+                    <transition cond="len(self.received_data) >= self.length or self.closed" target="../wait_for_header">
+                        <script>
+                            if self.length == float('inf'):
+                                data = self.received_data
+                                self.received_data = ""
+                            else:
+                                data = self.received_data[:self.length]
+                                self.received_data = self.received_data[self.length:]
+
+                            # We support POST data only, so everything is in the data
+                            try:
+                                params = dict([p.split('=') for p in data.split('&amp;')])
+                                data = {k: urllib.unquote_plus(v) for k, v in params.iteritems()}
+                            except:
+                                data = {}
+                        </script>
+                        <raise event="HTTP_output" scope="narrow" target="'parent'">
+                            <parameter expr="self.association_name"/>
+                            <parameter expr="data"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+            <transition event="close" target="../close"/>
+        </parallel>
+        <state id="close">
+            <onentry>
+                <raise port="socket_out" event="close_socket">
+                    <parameter expr="self.socket"/>
+                </raise>
+                <raise scope="narrow" target="'parent'" event="close_socket">
+                    <parameter expr="self.association_name"/>
+                </raise>
+            </onentry>
+        </state>
+    </scxml>
+</class>

+ 2 - 0
hybrid_server/compile.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+python python_sccd_compiler/sccdc.py -p threads server.xml

+ 17 - 0
hybrid_server/python_runtime/.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>python_runtime</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>

+ 5 - 0
hybrid_server/python_runtime/.pydevproject

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>

+ 0 - 0
hybrid_server/python_runtime/__init__.py


+ 9 - 0
hybrid_server/python_runtime/accurate_time.py

@@ -0,0 +1,9 @@
+import time as t
+import os
+
+if os.name == 'posix':
+	def time():
+		return t.time()
+elif os.name == 'nt':
+	def time():
+		return t.clock()

+ 58 - 0
hybrid_server/python_runtime/event_queue.py

@@ -0,0 +1,58 @@
+from infinity import INFINITY
+
+class EventQueue(object):
+    class EventQueueEntry(object):        
+        def __init__(self, event_list, time_offset) :
+            self.event_list = event_list
+            self.time_offset = time_offset
+        
+        def decreaseTime(self, offset) :
+            self.time_offset -= offset;   
+        
+        def getEvents(self) :
+            return self.event_list
+        
+        def getTime (self) :
+            return self.time_offset
+
+    def __init__(self):
+        self.event_list = []
+
+    def add(self, event_list, time_offset) :
+        entry = EventQueue.EventQueueEntry(event_list, time_offset);
+        #We maintain a sorted stable list
+        insert_index = 0;
+        index = len(self.event_list)-1
+        while (index >= 0) :
+            if (self.event_list[index].getTime() <= time_offset) :
+                insert_index = index + 1;
+                break;
+            index -= 1
+        self.event_list.insert(insert_index, entry)
+    
+    def decreaseTime(self, offset) :
+        for event in self.event_list :
+            event.decreaseTime(offset)
+    
+    def isEmpty(self) :
+        return len(self.event_list) == 0
+    
+    def getEarliestTime(self) :
+        """Returns the earliest time. INFINITY if no events are present."""
+        if self.isEmpty() :
+            return INFINITY
+        else :
+            return self.event_list[0].getTime()
+    
+    def popDueEvents(self) :
+        result = []
+        if (self.isEmpty() or self.event_list[0].getTime() > 0.0) :
+            #There are no events, or the earliest event isn't due, so we can already return an emtpy result
+            return result
+
+        index = 0;
+        while (index < len(self.event_list) and self.event_list[index].getTime() <= 0.0) :
+            result.append(self.event_list[index].getEvents()) #Add all events that are due (offset less than 0) to the result
+            index += 1
+        self.event_list = self.event_list[len(result):]
+        return result;

+ 3 - 0
hybrid_server/python_runtime/infinity.py

@@ -0,0 +1,3 @@
+# Instantiate singleton:        
+INFINITY = float('inf')
+

+ 1 - 0
hybrid_server/python_runtime/libs/__init__.py

@@ -0,0 +1 @@
+

+ 59 - 0
hybrid_server/python_runtime/libs/drawing.py

@@ -0,0 +1,59 @@
+"""
+ *REALLY* Small framework for creating/manipulating/deleting Tkinter Canvas elements.
+ 
+ NOTE: keep this synced with svg.js
+ 
+ Author: Raphael Mannadiar
+ Date: 2014/08/21
+"""
+
+from utils import utils
+
+
+class drawing:
+    class canvas_wrapper:
+        def __init__(self, element):
+            self.element = element
+            self.width = int(element.cget("width"))
+            self.height = int(element.cget("height"))
+
+        def add_circle(self, x, y, r, style):
+            new_element_id = self.element.create_oval(x-r, y-r, x+r, y+r, **style)
+            return drawing.ui_element_wrapper(self, new_element_id, x, y)
+
+        def add_rectangle(self, x, y, w, h, style):
+            new_element_id = self.element.create_rectangle(x-w/2.0, y-h/2.0, x+w/2.0, y+h/2.0, **style)
+            return drawing.ui_element_wrapper(self, new_element_id, x, y)
+
+        def remove_element(self, element):
+            self.element.delete(element.element_id)
+
+
+    class ui_element_wrapper:
+        def __init__(self, canvas_wrapper, element_id, x, y):
+            self.canvas_wrapper = canvas_wrapper
+            self.element_id = element_id
+            self.a = 0
+            self.x = x
+            self.y = y
+
+        def set_position(self, x, y):
+            self.move(x-self.x, y-self.y)
+
+        def get_position(self):
+            return utils._bunch(x=self.x, y=self.y)
+
+        def move(self, dx, dy):
+            self.x += dx
+            self.y += dy
+            self.canvas_wrapper.element.move(self.element_id, dx, dy)
+
+        def set_rotation(self, a):
+            raise Exception("Not implemented yet")
+
+        def rotate(self, a):
+            raise Exception("Not implemented yet")
+
+        def set_color(self, color):
+            self.canvas_wrapper.element.itemconfig(self.element_id, fill=color)
+

+ 107 - 0
hybrid_server/python_runtime/libs/ui.py

@@ -0,0 +1,107 @@
+"""
+ *REALLY* Small framework for creating/manipulating/deleting gui elements in Tkinter.
+ 
+ NOTE: keep this synced with ui.js
+ 
+ Author: Raphael Mannadiar
+ Date: 2014/08/21
+"""
+
+import Tkinter as tk
+from python_runtime.statecharts_core import Event
+from drawing import drawing
+from utils import utils
+
+
+class ui:
+	window = None
+	__nextWindowId = 0
+
+	EVENTS = utils._bunch(
+		KEY_PRESS = 			'<Key>',
+		MOUSE_CLICK = 			'<Button>',
+		MOUSE_MOVE = 			'<Motion>',
+		MOUSE_PRESS =			'<ButtonPress>',
+		MOUSE_RELEASE =		'<ButtonRelease>',
+		MOUSE_RIGHT_CLICK =	'<Button-3>',
+		WINDOW_CLOSE = 		'WM_DELETE_WINDOW');
+
+	MOUSE_BUTTONS = utils._bunch(
+		LEFT		= 1,
+		MIDDLE	= 2,
+		RIGHT		= 3);
+
+	KEYCODES	= utils._bunch(
+		DELETE	= 46);
+
+	@staticmethod
+	def append_button(_window,text):
+		button = tk.Button(_window, text=text)
+		button.pack()
+		return ui.wrap_element(button)
+
+
+	@staticmethod
+	def append_canvas(_window,width,height,style):
+		canvas = tk.Canvas(_window,width=width,height=height)
+		canvas.config(**style)
+		canvas.pack()
+		return drawing.canvas_wrapper(canvas)
+
+
+	@staticmethod
+	def bind_event(source,event,controller,raise_name,port="ui",time_offset=0.0):
+
+		def __handle_event(ev=None):
+			if event == ui.EVENTS.KEY_PRESS :
+				controller.addInput(Event(raise_name, port, [ev.keycode,source]),time_offset)
+
+			elif event == ui.EVENTS.MOUSE_CLICK or \
+				  event == ui.EVENTS.MOUSE_MOVE or \
+				  event == ui.EVENTS.MOUSE_PRESS or \
+				  event == ui.EVENTS.MOUSE_RELEASE or \
+		  		  event == ui.EVENTS.MOUSE_RIGHT_CLICK :
+				controller.addInput(Event(raise_name, port, [ev.x, ev.y, ev.num]),time_offset)
+
+			elif event == ui.EVENTS.WINDOW_CLOSE :
+				controller.addInput(Event(raise_name, port, [source]),time_offset)
+
+			else :
+				raise Exception('Unsupported event');
+	
+		if event == ui.EVENTS.WINDOW_CLOSE :
+			source.protocol(event, __handle_event)
+
+		elif issubclass(drawing.ui_element_wrapper,source.__class__) :
+			source.canvas_wrapper.element.tag_bind(source.element_id, event, __handle_event)
+
+		else :
+			source.bind(event, __handle_event)
+
+
+	@staticmethod
+	def close_window(_window):
+		_window.destroy()
+
+
+	@staticmethod
+	def log(value):
+		print(value)
+
+
+	@staticmethod
+	def new_window(width,height):
+		_window = tk.Toplevel(ui.window)
+		_window.geometry(str(width)+"x"+str(height)+"+300+300")
+		return _window
+
+
+	@staticmethod
+	def println(value,target):
+		raise Exception('Not implemented yet');
+
+
+	@staticmethod
+	def wrap_element(element):
+		return utils._bunch(element=element)
+

+ 19 - 0
hybrid_server/python_runtime/libs/utils.py

@@ -0,0 +1,19 @@
+import random
+
+class utils:
+
+	@staticmethod
+	def random():
+		return random.random()
+
+
+	"""
+		provide "." access to dictionaries
+
+		example: d = {'a':1}
+			before: d['a'] => 1, d.a => error
+			after:  d['a'] = d.a
+	"""
+	class _bunch:
+  		def __init__(self, **kwds):
+ 			self.__dict__.update(kwds)

+ 22 - 0
hybrid_server/python_runtime/nextafter.py

@@ -0,0 +1,22 @@
+import imp
+
+try:
+	# if module 'numpy' exists, use it
+	found = imp.find_module('numpy')
+	nextafter = imp.load_module('numpy', *found).nextafter
+
+except ImportError:
+	import math
+	# this ad-hoc implementation won't always give the exact same result as the C implementation used by numpy, but it's good enough for our purposes
+	def nextafter(x, y):
+		m,e = math.frexp(x)
+		exp = e - 53
+		if exp < -1022 or m == 0.0:
+			exp = -1022
+		epsilon = math.ldexp(1.0, exp)
+		if y > x:
+			return x + epsilon
+		elif y < x:
+			return x - epsilon
+		else:
+			return x

+ 941 - 0
hybrid_server/python_runtime/statecharts_core.py

@@ -0,0 +1,941 @@
+import abc
+import re
+from accurate_time import time
+import threading
+import traceback
+import math
+from nextafter import nextafter
+from infinity import INFINITY
+from event_queue import EventQueue
+from Queue import Queue, Empty
+
+class RuntimeException(Exception):
+	def __init__(self, message):
+		self.message = message
+	def __str__(self):
+		return repr(self.message)
+
+class AssociationException(RuntimeException):
+	pass
+
+class AssociationReferenceException(RuntimeException):
+	pass
+
+class ParameterException(RuntimeException):
+	pass
+
+class InputException(RuntimeException):
+	pass
+
+class Association(object):
+	#wrapper object for one association relation
+	def __init__(self, to_class, min_card, max_card):
+		self.to_class = to_class
+		self.min_card = min_card
+		self.max_card = max_card
+		self.instances = {}  # maps index (as string) to instance
+		self.instances_to_ids = {}
+		self.size = 0
+		self.next_id = 0
+		
+
+	def allowedToAdd(self):
+		return self.max_card == -1 or self.size < self.max_card
+		
+	def allowedToRemove(self):
+		return self.min_card == -1 or self.size > self.min_card
+		
+	def addInstance(self, instance):
+		if self.allowedToAdd() :
+			new_id = self.next_id
+			self.next_id += 1
+			self.instances[new_id] = instance
+			self.instances_to_ids[instance] = new_id
+			self.size += 1
+			return new_id
+		else :
+			raise AssociationException("Not allowed to add the instance to the association.")
+		
+	def removeInstance(self, instance):
+		if self.allowedToRemove() :
+			del self.instances[self.instances_to_ids[instance]]
+			del self.instances_to_ids[instance]
+			self.size -= 1
+		else :
+			raise AssociationException("Not allowed to remove the instance from the association.")
+		
+	def getInstance(self, index):
+		try :
+			return self.instances[index]
+		except IndexError :
+			raise AssociationException("Invalid index for fetching instance(s) from association.")
+
+"""class InstanceWrapper(object):
+	#wrapper object for an instance and its relevant information needed in the object manager
+	def __init__(self, instance, associations):
+		self.instance = instance
+		self.associations = {}
+		for association in associations :
+			self.associations[association.getName()] = association  
+		
+	def getAssociation(self, name):
+		try :
+			return self.associations[name]
+		except KeyError :
+			raise AssociationReferenceException("Unknown association %s." % name)
+	
+	def getInstance(self):
+		return self.instance"""
+
+class ObjectManagerBase(object):
+	__metaclass__  = abc.ABCMeta
+	
+	def __init__(self, controller):
+		self.controller = controller
+		self.events = EventQueue()
+		self.instances = set() #a dictionary that maps RuntimeClassBase to InstanceWrapper
+		
+	def addEvent(self, event, time_offset = 0.0):
+		self.events.add(event, time_offset)
+		
+	# Broadcast an event to all instances
+	def broadcast(self, new_event):
+		for i in self.instances:
+			i.addEvent(new_event)
+		
+	def getWaitTime(self):  
+		#first get waiting time of the object manager's events
+		smallest_time = self.events.getEarliestTime()
+		#check all the instances
+		for instance in self.instances:
+			smallest_time = min(smallest_time, instance.getEarliestEventTime())
+		return smallest_time
+	
+	def stepAll(self, delta):
+		self.step(delta)
+		for i in self.instances:
+			i.step(delta)
+
+	def step(self, delta):
+		self.events.decreaseTime(delta)
+		for event in self.events.popDueEvents() :
+			self.handleEvent(event)
+			   
+	def start(self):
+		for i in self.instances:
+			i.start()		  
+			   
+	def handleEvent(self, e):   
+		if e.getName() == "narrow_cast" :
+			self.handleNarrowCastEvent(e.getParameters())
+			
+		elif e.getName() == "broad_cast" :
+			self.handleBroadCastEvent(e.getParameters())
+			
+		elif e.getName() == "create_instance" :
+			self.handleCreateEvent(e.getParameters())
+			
+		elif e.getName() == "associate_instance" :
+			self.handleAssociateEvent(e.getParameters())
+			
+		elif e.getName() == "start_instance" :
+			self.handleStartInstanceEvent(e.getParameters())
+			
+		elif e.getName() == "delete_instance" :
+			self.handleDeleteInstanceEvent(e.getParameters())
+			
+	def processAssociationReference(self, input_string):
+		if len(input_string) == 0 :
+			raise AssociationReferenceException("Empty association reference.")
+		regex_pattern = re.compile("^([a-zA-Z_]\w*)(?:\[(\d+)\])?$")
+		path_string =  input_string.split("/")
+		result = []
+		for piece in path_string :
+			match = regex_pattern.match(piece)
+			if match :
+				name = match.group(1)
+				index = match.group(2)
+				if index is None :
+					index = -1
+				result.append((name,int(index)))
+			else :
+				raise AssociationReferenceException("Invalid entry in association reference. Input string: " + input_string)
+		return result
+	
+	def handleStartInstanceEvent(self, parameters):
+		if len(parameters) != 2 :
+			raise ParameterException ("The start instance event needs 2 parameters.")  
+		else :
+			source = parameters[0]
+			traversal_list = self.processAssociationReference(parameters[1])
+			for i in self.getInstances(source, traversal_list) :
+				i["instance"].start()
+			source.addEvent(Event("instance_started", parameters = [parameters[1]]))
+		
+	def handleBroadCastEvent(self, parameters):
+		if len(parameters) != 1 :
+			raise ParameterException ("The broadcast event needs 1 parameter.")
+		self.broadcast(parameters[0])
+
+	def handleCreateEvent(self, parameters):
+		if len(parameters) < 2 :
+			raise ParameterException ("The create event needs at least 2 parameters.")
+
+		source = parameters[0]
+		association_name = parameters[1]
+		
+		association = source.associations[association_name]
+		#association = self.instances_map[source].getAssociation(association_name)
+		if association.allowedToAdd() :
+			''' allow subclasses to be instantiated '''
+			class_name = association.to_class if len(parameters) == 2 else parameters[2]
+			new_instance = self.createInstance(class_name, parameters[3:])
+			if not new_instance:
+				raise ParameterException("Creating instance: no such class: " + class_name)
+			#index = association.addInstance(new_instance)
+			try:
+				index = association.addInstance(new_instance)
+			except AssociationException as exception:
+				raise RuntimeException("Error adding instance to association '" + association_name + "': " + str(exception))
+			p = new_instance.associations.get("parent")
+			if p:
+				p.addInstance(source)
+			source.addEvent(Event("instance_created", None, [association_name+"["+str(index)+"]"]))
+		else :
+			source.addEvent(Event("instance_creation_error", None, [association_name]))
+
+	def handleDeleteInstanceEvent(self, parameters):
+		if len(parameters) < 2 :
+			raise ParameterException ("The delete event needs at least 2 parameters.")
+		else :
+			source = parameters[0]
+			association_name = parameters[1]
+			traversal_list = self.processAssociationReference(association_name)
+			instances = self.getInstances(source, traversal_list)
+			#association = self.instances_map[source].getAssociation(traversal_list[0][0])
+			association = source.associations[traversal_list[0][0]]
+			for i in instances:
+				try:
+					association.removeInstance(i["instance"])
+					self.instances.discard(i["instance"])
+				except AssociationException as exception:
+					raise RuntimeException("Error removing instance from association '" + association_name + "': " + str(exception))
+				i["instance"].stop()
+				#if hasattr(i.instance, 'user_defined_destructor'):
+				i["instance"].user_defined_destructor()
+			source.addEvent(Event("instance_deleted", parameters = [parameters[1]]))
+				
+	def handleAssociateEvent(self, parameters):
+		if len(parameters) != 3 :
+			raise ParameterException ("The associate_instance event needs 3 parameters.")
+		else :
+			source = parameters[0]
+			to_copy_list = self.getInstances(source,self.processAssociationReference(parameters[1]))
+			if len(to_copy_list) != 1 :
+				raise AssociationReferenceException ("Invalid source association reference.")
+			wrapped_to_copy_instance = to_copy_list[0]["instance"]
+			dest_list = self.processAssociationReference(parameters[2])
+			if len(dest_list) == 0 :
+				raise AssociationReferenceException ("Invalid destination association reference.")
+			last = dest_list.pop()
+			if last[1] != -1 :
+				raise AssociationReferenceException ("Last association name in association reference should not be accompanied by an index.")
+				
+			for i in self.getInstances(source, dest_list) :
+				i["instance"].associations[last[0]].addInstance(wrapped_to_copy_instance)
+		
+	def handleNarrowCastEvent(self, parameters):
+		if len(parameters) != 3 :
+			raise ParameterException ("The associate_instance event needs 3 parameters.")
+		source = parameters[0]
+		traversal_list = self.processAssociationReference(parameters[1])
+		cast_event = parameters[2]
+		for i in self.getInstances(source, traversal_list) :
+			i["instance"].addEvent(cast_event)
+		
+	def getInstances(self, source, traversal_list):
+		currents = [{
+			"instance" : source,
+			"ref" : None,
+			"assoc_name" : None,
+			"assoc_index" : None
+		}]
+		#currents = [source]
+		for (name, index) in traversal_list :
+			nexts = []
+			for current in currents :
+				association = current["instance"].associations[name]
+				if (index >= 0 ) :
+					nexts.append({
+						"instance" : association.instances[index],
+						"ref" : current["instance"],
+						"assoc_name" : name,
+						"assoc_index" : index
+					})
+				elif (index == -1) :
+					for i in association.instances:
+						nexts.append({
+							"instance" : association.instances[i],
+							"ref" : current["instance"],
+							"assoc_name" : name,
+							"assoc_index" : index
+						})
+					#nexts.extend( association.instances.values() )
+				else :
+					raise AssociationReferenceException("Incorrect index in association reference.")
+			currents = nexts
+		return currents
+			
+	@abc.abstractmethod
+	def instantiate(self, class_name, construct_params):
+		pass
+		
+	def createInstance(self, to_class, construct_params = []):
+		instance = self.instantiate(to_class, construct_params)
+		self.instances.add(instance)
+		return instance
+	
+class Event(object):
+	def __init__(self, event_name, port = "", parameters = []):
+		self.name = event_name
+		self.parameters = parameters
+		self.port = port
+
+	def getName(self):
+		return self.name
+
+	def getPort(self):
+		return self.port
+
+	def getParameters(self):
+		return self.parameters
+	
+	def __repr__(self):
+		representation = "(event name : " + str(self.name) + "; port : " + str(self.port)
+		if self.parameters :
+			representation += "; parameters : " + str(self.parameters)
+		representation += ")"
+		return representation
+	
+class OutputListener(object):
+	def __init__(self, port_names):
+		self.port_names = port_names
+		self.queue = Queue()
+
+	def add(self, event):
+		if len(self.port_names) == 0 or event.getPort() in self.port_names :
+			self.queue.put_nowait(event)
+			
+	""" Tries for timeout seconds to fetch an event, returns None if failed.
+		0 as timeout means no waiting (blocking), returns None if queue is empty.
+		-1 as timeout means blocking until an event can be fetched. """
+	def fetch(self, timeout = 0):
+		if timeout < 0:
+			timeout = INFINITY
+		while timeout >= 0:
+			try:
+				# wait in chunks of 100ms because we
+				# can't receive (keyboard)interrupts while waiting
+				return self.queue.get(True, 0.1 if timeout > 0.1 else timeout)
+			except Empty:
+				timeout -= 0.1
+		return None
+
+class InputPortEntry(object):
+	def __init__(self, virtual_name, instance):
+		self.virtual_name = virtual_name
+		self.instance = instance
+		
+class ControllerBase(object):
+
+	def __init__(self, object_manager):
+		self.object_manager = object_manager
+
+		self.private_port_counter = 0
+
+		# Keep track of input ports
+		self.input_ports = {}
+		self.input_queue = EventQueue()
+
+		# Keep track of output ports
+		self.output_ports = []
+		self.output_listeners = []
+
+		# Let statechart run one last time before stopping
+		self.done = False
+			
+	def addInputPort(self, virtual_name, instance = None):
+		if instance == None :
+			port_name = virtual_name
+		else:
+			port_name = "private_" + str(self.private_port_counter) + "_" + virtual_name
+			self.private_port_counter += 1
+		self.input_ports[port_name] = InputPortEntry(virtual_name, instance)
+		return port_name
+		
+	def addOutputPort(self, port_name):
+		self.output_ports.append(port_name)
+
+	def broadcast(self, new_event):
+		self.object_manager.broadcast(new_event)
+		
+	def start(self):
+		self.object_manager.start()
+	
+	def stop(self):
+		pass
+
+	def addInput(self, input_event_list, time_offset = 0.0):
+		if not isinstance(input_event_list, list):
+			input_event_list = [input_event_list]
+
+		for e in input_event_list:
+			if e.getName() == ""  :
+				raise InputException("Input event can't have an empty name.")
+		
+			if e.getPort() not in self.input_ports :
+				raise InputException("Input port mismatch, no such port: " + e.getPort() + ".")	 
+
+		self.input_queue.add(input_event_list, time_offset)
+
+	def getWaitTime(self):
+		return min(self.object_manager.getWaitTime(), self.input_queue.getEarliestTime())
+
+	def handleInput(self, delta):
+		self.input_queue.decreaseTime(delta)
+		for events in self.input_queue.popDueEvents():
+			for e in events:
+				input_port = self.input_ports[e.getPort()]
+				e.port = input_port.virtual_name
+				target_instance = input_port.instance
+				if target_instance == None:
+					self.broadcast(e)
+				else:
+					target_instance.addEvent(e)
+
+	def outputEvent(self, event):
+		for listener in self.output_listeners :
+			listener.add(event)
+
+	def addOutputListener(self, ports):
+		listener = OutputListener(ports)
+		self.output_listeners.append(listener)
+		return listener
+
+	def addMyOwnOutputListener(self, listener):
+		self.output_listeners.append(listener)
+
+	# deprecated, to add multiple events, use addInput instead
+	def addEventList(self, event_list):
+		for (event, time_offset) in event_list :
+			self.addInput(event, time_offset)
+			
+	def getObjectManager(self):
+		return self.object_manager
+		
+class GameLoopControllerBase(ControllerBase):
+	def __init__(self, object_manager):
+		ControllerBase.__init__(self, object_manager)
+		
+	def update(self, delta):
+		self.handleInput(delta)
+		self.object_manager.stepAll(delta)
+
+class EventLoop:
+	# parameters:
+	#  schedule - a callback scheduling another callback in the event loop
+	#      this callback should take 2 parameters: (callback, timeout) and return an ID
+	#  clear - a callback that clears a scheduled callback
+	#      this callback should take an ID that was returned by 'schedule'
+	def __init__(self, schedule, clear):
+		self.schedule_callback = schedule
+		self.clear_callback = clear
+		self.scheduled_id = None
+		self.last_time = None
+		self.next_wakeup = None
+		self.last_print = 0.0
+
+	def getScheduledTimeout(self):
+		if self.last_time and self.next_wakeup:
+			return self.next_wakeup - self.last_time
+		else:
+			return INFINITY
+
+	# schedule relative to last_time
+	#
+	# argument 'wait_time' is the amount of virtual (simulated) time to wait
+	#
+	# NOTE: if the next wakeup (in simulated time) is in the past, the timeout is '0',
+	# but because scheduling '0' timeouts hurts performance, we don't schedule anything
+	# and return False instead
+	def schedule(self, f, wait_time):
+		if self.scheduled_id:
+			# if the following error occurs, it is probably due to a flaw in the logic of EventLoopControllerBase
+			raise RuntimeException("EventLoop class intended to maintain at most 1 scheduled callback.")
+
+		if wait_time == INFINITY:
+			self.last_time = None
+			self.next_wakeup = None
+			is_scheduled = True
+		else:
+			now = time()
+			if not self.last_time:
+				self.last_time = now
+			self.next_wakeup = self.last_time + wait_time
+			# self.last_time is a very large value, and wait_time can be very small, so 
+			if self.next_wakeup - self.last_time < wait_time:
+				# due to floating point imprecision, it is possible for a nonzero wait-time to advance simulated time not enough to pop the next event, potentially even causing the model to hang, so we always take the ceil of the exact result of the addition self.last_time + wait_time.
+				self.next_wakeup = nextafter(self.next_wakeup, INFINITY)
+			remaining = max(self.next_wakeup - now, 0.0)
+			is_scheduled, self.scheduled_id = self.schedule_callback(f, remaining)
+		return is_scheduled
+
+	def clear(self):
+		if self.scheduled_id:
+			self.clear_callback(self.scheduled_id)
+			self.scheduled_id = None
+
+	def nextDelta(self):
+		now = time()
+		if self.next_wakeup:
+			simulated_now = self.next_wakeup
+		else:
+			simulated_now = now
+		if now - self.last_print > 1.0:
+			behind_schedule = now - simulated_now
+			if behind_schedule > 0.1:
+				print "Warning: running %.f ms behind schedule" % (behind_schedule*1000.0)
+				self.last_print = now
+		if self.last_time:
+			delta = simulated_now - self.last_time
+		else:
+			delta = 0.0
+		self.last_time = simulated_now
+		self.next_wakeup = None
+		return delta
+
+	# returns elapsed time since delta
+	def elapsed(self):
+		if self.last_time:
+			return time() - self.last_time
+		else:
+			return 0.0
+
+class EventLoopControllerBase(ControllerBase):
+	def __init__(self, object_manager, event_loop, finished_callback = None):
+		ControllerBase.__init__(self, object_manager)
+		self.event_loop = event_loop
+		self.finished_callback = finished_callback
+
+	def addInput(self, input_event, time_offset = 0.0):
+		elapsed = self.event_loop.elapsed()
+		controller_timeout = time_offset + elapsed
+		ControllerBase.addInput(self, input_event, controller_timeout)
+		if controller_timeout < self.event_loop.getScheduledTimeout():
+			# added event's timeout is sooner than existing timeout -> re-schedule
+			self.event_loop.clear()
+			if not self.event_loop.schedule(self.run, controller_timeout):
+				self.run()
+
+	def start(self):
+		ControllerBase.start(self)
+		self.run()
+
+	def stop(self):
+		self.event_loop.clear()
+		ControllerBase.stop(self)
+
+	def run(self):
+		while True:
+			# clear existing timeout
+			self.event_loop.clear()
+			# calculate last time since simulation
+			delta = self.event_loop.nextDelta()
+			# simulate
+			self.handleInput(delta)
+			self.object_manager.stepAll(delta)
+			# schedule next timeout
+			wait_time = self.getWaitTime()
+			scheduled = self.event_loop.schedule(self.run, wait_time)
+			if wait_time == INFINITY:
+				if self.finished_callback:
+					self.finished_callback()
+			if scheduled:
+				break
+		
+class ThreadsControllerBase(ControllerBase):
+	def __init__(self, object_manager, keep_running):
+		ControllerBase.__init__(self, object_manager)
+		self.keep_running = keep_running
+		self.input_condition = threading.Condition()
+		self.stop_thread = False
+		self.thread = threading.Thread(target=self.run)
+		
+	def handleInput(self, delta):
+		with self.input_condition:
+		    ControllerBase.handleInput(self, delta)
+		
+	def start(self):
+		self.thread.start()
+		
+	def stop(self):
+		with self.input_condition:
+		    self.stop_thread = True
+		    self.input_condition.notifyAll()
+
+	def getWaitTime(self):
+		"""Compute time untill earliest next event"""
+		with self.input_condition:
+		    wait_time = ControllerBase.getWaitTime(self)
+
+		if wait_time == INFINITY :
+			if self.done :
+				self.done = False
+			else :
+				self.done = True
+				return 0.0
+		return wait_time
+
+	def handleWaiting(self):
+		with self.input_condition:
+		    wait_time = self.getWaitTime()
+		    if(wait_time <= 0.0):
+			    return
+		    
+		    if wait_time == INFINITY :
+			    if self.keep_running :
+				    self.input_condition.wait() #Wait for a signals
+			    else :
+				    self.stop_thread = True
+		    
+		    elif wait_time != 0.0 :
+			    reduced_wait_time = wait_time - (time() - self.last_recorded_time)
+			    if reduced_wait_time > 0.0 :
+				    self.input_condition.wait(reduced_wait_time)    
+
+	def run(self):
+		self.last_recorded_time  = time()
+		super(ThreadsControllerBase, self).start()
+		last_iteration_time = 0.0
+		
+		while True:
+			with self.input_condition:
+			    self.handleInput(last_iteration_time)
+			#Compute the new state based on internal events
+			self.object_manager.stepAll(last_iteration_time)
+			
+			self.handleWaiting()
+			
+			with self.input_condition:
+			    if self.stop_thread : 
+				    break
+			
+			previous_recorded_time = self.last_recorded_time
+			self.last_recorded_time = time()
+			last_iteration_time = self.last_recorded_time - previous_recorded_time
+		
+	def join(self):
+		self.thread.join()
+
+	def addInput(self, input_event, time_offset = 0.0):
+		with self.input_condition:
+		    super(ThreadsControllerBase, self).addInput(input_event, time_offset)
+		    self.input_condition.notifyAll()
+
+	def addEventList(self, event_list):
+		with self.input_condition:
+		    super(ThreadsControllerBase, self).addEventList(event_list)
+
+class StatechartSemantics:
+	# Big Step Maximality
+	TakeOne = 0
+	TakeMany = 1
+	# Concurrency - not implemented yet
+	Single = 0
+	Many = 1
+	# Preemption - not implemented yet
+	NonPreemptive = 0
+	Preemptive = 1
+	# Internal Event Lifeline
+	Queue = 0
+	NextSmallStep = 1
+	NextComboStep = 2
+	# Input Event Lifeline
+	Whole = 0
+	FirstSmallStep = 1
+	FirstComboStep = 2
+	# Priority
+	SourceParent = 0
+	SourceChild = 1
+	# TODO: add Memory Protocol options
+	
+	def __init__(self):
+		# default semantics:
+		self.big_step_maximality = self.TakeMany
+		self.concurrency = self.Single
+		self.internal_event_lifeline = self.Queue
+		#self.input_event_lifeline = self.FirstComboStep
+		self.input_event_lifeline = self.FirstSmallStep
+		self.priority = self.SourceParent
+
+class RuntimeClassBase(object):
+	__metaclass__  = abc.ABCMeta
+	
+	def __init__(self, controller):
+		self.active = False
+		self.is_stable = True
+		self.events = EventQueue()
+
+		self.controller = controller
+
+		self.timers = None
+		self.inports = {}
+
+		self.semantics = StatechartSemantics()
+
+	def start(self):
+		self.current_state = {}
+		self.history_state = {}
+		self.timers = {}
+
+		self.big_step = BigStepState()
+		self.combo_step = ComboStepState()
+		self.small_step = SmallStepState()
+
+		self.active = True
+		self.is_stable = False
+
+		self.initializeStatechart()
+		self.processBigStepOutput()
+	
+	def stop(self):
+		self.active = False
+		
+	def addEvent(self, event_list, time_offset = 0.0):
+		if not isinstance(event_list, list):
+			event_list = [event_list]
+		self.events.add(event_list, time_offset)
+		
+	def getEarliestEventTime(self) :
+		if not self.active:
+			return INFINITY
+		if not self.is_stable:
+			return 0.0
+		if self.timers:
+			return min(self.events.getEarliestTime(), min(self.timers.itervalues()))
+		return self.events.getEarliestTime()
+
+	def processBigStepOutput(self):
+		for e in self.big_step.getOutputEvents():
+			self.controller.outputEvent(e)
+		for e in self.big_step.getOutputEventsOM():
+			self.controller.object_manager.addEvent(e)
+
+	def step(self, delta):
+		if not self.active :
+			return
+		
+		# decrease event queue time
+		self.events.decreaseTime(delta)
+
+		# decrease timers time
+		next_timers = {}
+		for (key,value) in self.timers.iteritems() :
+			time = value - delta
+			if time <= 0.0 :
+				self.addEvent( Event("_" + str(key) + "after"), time)
+			else :
+				next_timers[key] = time
+		self.timers = next_timers
+
+		# execute big step(s)
+		due = self.events.popDueEvents()
+		if not due and not self.is_stable:
+			due = [[]]
+		for input_events in due:
+			# perform 1 big step per slot in 'due'
+			self.is_stable = not self.bigStep(input_events)
+			self.processBigStepOutput()
+
+	def inState(self, nodes):
+		for c in self.current_state.itervalues():
+			new_nodes = []
+			for n in nodes:
+				if not (n in c):
+					new_nodes.append(n)
+			nodes = new_nodes
+			if len(nodes) == 0:
+				return True
+		return False
+
+	def bigStep(self, input_events):
+		#print "new big step"
+		self.big_step.next(input_events)
+		self.small_step.reset()
+		self.combo_step.reset()
+		while self.comboStep():
+			self.big_step.setStepped()
+			if self.semantics.big_step_maximality == StatechartSemantics.TakeOne:
+				break # Take One -> only one combo step allowed
+		return self.big_step.hasStepped()
+
+	def comboStep(self):
+		#print "new combo step"
+		self.combo_step.next()
+		while self.smallStep():
+			self.combo_step.setStepped()
+		return self.combo_step.hasStepped()
+
+	def smallStep(self):
+		if self.small_step.hasStepped():
+			self.small_step.next()
+		self.generateCandidates()
+		if self.small_step.hasCandidates():
+			#print "new small step, have " + str(len(self.small_step.getCandidates())) + " candidates"
+			if self.semantics.concurrency == StatechartSemantics.Single:
+				transition, parameters = self.small_step.getCandidates()[0] # execute first of candidates
+				transition(parameters)
+			elif self.semantics.concurrency == StatechartSemantics.Many:
+				pass # TODO: implement
+			self.small_step.setStepped()
+		return self.small_step.hasStepped()
+
+	def getEnabledEvents(self):
+		result = self.small_step.getCurrentEvents() + self.combo_step.getCurrentEvents()
+		if self.semantics.input_event_lifeline == StatechartSemantics.Whole or (
+			not self.big_step.hasStepped() and
+				(self.semantics.input_event_lifeline == StatechartSemantics.FirstComboStep or (
+				not self.combo_step.hasStepped() and
+					self.semantics.input_event_lifeline == StatechartSemantics.FirstSmallStep))):
+			result += self.big_step.getInputEvents()
+		return result
+
+	def raiseInternalEvent(self, event):
+		if self.semantics.internal_event_lifeline == StatechartSemantics.NextSmallStep:
+			self.small_step.addNextEvent(event)
+		elif self.semantics.internal_event_lifeline == StatechartSemantics.NextComboStep:
+			self.combo_step.addNextEvent(event)
+		elif self.semantics.internal_event_lifeline == StatechartSemantics.Queue:
+			self.events.add([event], 0.0)
+
+	@abc.abstractmethod
+	def initializeStatechart(self):
+		pass
+
+	@abc.abstractmethod
+	def generateCandidates(self):
+		pass
+
+
+class BigStepState(object):
+	def __init__(self):
+		self.input_events = [] # input events received from environment before beginning of big step (e.g. from object manager, from input port)
+		self.output_events_port = [] # output events to be sent to output port after big step ends.
+		self.output_events_om = [] # output events to be sent to object manager after big step ends.
+		self.has_stepped = True
+
+	def next(self, input_events):
+		self.input_events = input_events
+		self.output_events_port = []
+		self.output_events_om = []
+		self.has_stepped = False
+
+	def getInputEvents(self):
+		return self.input_events
+
+	def getOutputEvents(self):
+		return self.output_events_port
+
+	def getOutputEventsOM(self):
+		return self.output_events_om
+
+	def outputEvent(self, event):
+		self.output_events_port.append(event)
+
+	def outputEventOM(self, event):
+		self.output_events_om.append(event)
+
+	def setStepped(self):
+		self.has_stepped = True
+
+	def hasStepped(self):
+		return self.has_stepped
+
+
+class ComboStepState(object):
+	def __init__(self):
+		self.current_events = [] # set of enabled events during combo step
+		self.next_events = [] # internal events that were raised during combo step
+		self.changed = [] # set of all or-states that were the arena of a triggered transition during big step.
+		self.has_stepped = True
+
+	def reset(self):
+		self.current_events = []
+		self.next_events = []
+
+	def next(self):
+		self.current_events = self.next_events
+		self.next_events = []
+		self.changed = []
+		self.has_stepped = False
+
+	def addNextEvent(self, event):
+		self.next_events.append(event)
+
+	def getCurrentEvents(self):
+		return self.current_events
+
+	def setArenaChanged(self, arena):
+		self.changed.append(arena)
+
+	def isArenaChanged(self, arena):
+		return (arena in self.changed)
+
+	def isStable(self):
+		return (len(self.changed) == 0)
+
+	def setStepped(self):
+		self.has_stepped = True
+
+	def hasStepped(self):
+		return self.has_stepped
+
+
+class SmallStepState(object):
+	def __init__(self):
+		self.current_events = [] # set of enabled events during small step
+		self.next_events = [] # events to become 'current' in the next small step
+		self.candidates = [] # document-ordered(!) list of transitions that can potentially be executed concurrently, or preempt each other, depending on concurrency semantics. If no concurrency is used and there are multiple candidates, the first one is chosen. Source states of candidates are *always* orthogonal to each other.
+		self.has_stepped = True
+
+	def reset(self):
+		self.current_events = []
+		self.next_events = []
+
+	def next(self):
+		self.current_events = self.next_events # raised events from previous small step
+		self.next_events = []
+		self.candidates = []
+		self.has_stepped = False
+
+	def addNextEvent(self, event):
+		self.next_events.append(event)
+
+	def getCurrentEvents(self):
+		return self.current_events
+
+	def addCandidate(self, t, p):
+		self.candidates.append((t, p))
+
+	def getCandidates(self):
+		return self.candidates
+
+	def hasCandidates(self):
+		return len(self.candidates) > 0
+
+	def setStepped(self):
+		self.has_stepped = True
+
+	def hasStepped(self):
+		return self.has_stepped
+

+ 21 - 0
hybrid_server/python_runtime/tkinter_eventloop.py

@@ -0,0 +1,21 @@
+from statecharts_core import EventLoop
+import math
+
+class TkEventLoop(EventLoop):
+	def __init__(self, tk):
+	
+		tk.sccd_force_update = False
+
+		# bind scheduler callback
+		def schedule(callback, timeout):
+			if timeout == 0:
+			# tk considers updating the window an 'idle' task, only to be done if no events are scheduled for a while. But this has the downside of the interface becoming completely unresponsive while the model is performing steps with no gaps in between. Thus we insert an 'update_idletasks()' to obtain "javascript event loop"-like behavior.
+				if tk.sccd_force_update:
+					tk.update_idletasks()
+					tk.sccd_force_update = False
+				else:
+					return (False, None) # don't schedule 0-timeout, it's more performant to just keep running
+			return (True, tk.after(int(math.ceil(timeout*1000.0)), callback))
+
+		EventLoop.__init__(self, schedule, tk.after_cancel)
+

+ 17 - 0
hybrid_server/python_sccd_compiler/.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>python_sccd_compiler</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>

+ 5 - 0
hybrid_server/python_sccd_compiler/.pydevproject

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+</pydev_project>

+ 0 - 0
hybrid_server/python_sccd_compiler/__init__.py


+ 14 - 0
hybrid_server/python_sccd_compiler/compiler_exceptions.py

@@ -0,0 +1,14 @@
+class CompilerException(Exception):
+	def __init__(self, message):
+		self.message = message
+	def __str__(self):
+		return repr(self.message)
+	
+class TransitionException(CompilerException):
+	pass
+
+class UnprocessedException(CompilerException):
+	pass
+
+class CodeBlockException(CompilerException):
+	pass

+ 911 - 0
hybrid_server/python_sccd_compiler/generic_generator.py

@@ -0,0 +1,911 @@
+# Generic Generator by Joeri Exelmans
+#
+# Visits SCCD-domain constructs (see sccd_constructs.py) and converts them
+# to a generic language AST (see generic_language_constructs.py), that can
+# then be visited by a target language writer.
+
+import traceback
+
+import time
+from utils import Enum, Logger
+
+from visitor import Visitor
+from sccd_constructs import FormalParameter
+from stateful_writer import StatefulWriter
+import generic_language_constructs as GLC
+
+Platforms = Enum("Threads","GameLoop","EventLoop") 
+
+class GenericGenerator(Visitor):
+	
+	def __init__(self, platform):
+		self.platform = platform
+		self.writer = StatefulWriter()
+
+	def generic_visit(self, node):
+		Logger.showWarning("GenericGenerator has no visit method for node of type '" + str(type(node)) + "'.")
+
+	def get(self):
+		return self.writer.get()
+
+	def visit_ClassDiagram(self, class_diagram):
+		header = ("Generated by Statechart compiler by Glenn De Jonghe and Joeri Exelmans\n"
+		          "\n"
+		          "Date:   " + time.asctime() + "\n")
+		if class_diagram.name or class_diagram.author or class_diagram.description:
+			header += "\n"
+		if class_diagram.author:
+			header += "Model author: " + class_diagram.author + "\n"
+		if class_diagram.name:
+			header += "Model name:   " + class_diagram.name + "\n"
+		if class_diagram.description.strip():
+			header += "Model description:\n"
+			header += class_diagram.description.strip()
+
+		self.writer.addMultiLineComment(header)
+		self.writer.addVSpace()
+		self.writer.addInclude(([GLC.RuntimeModuleIdentifier(), "statecharts_core"]))
+		if class_diagram.top.strip():
+			self.writer.addRawCode(class_diagram.top)
+		self.writer.addVSpace()
+
+		self.writer.beginPackage(class_diagram.name)
+		
+		#visit children
+		for c in class_diagram.classes :
+			c.accept(self)
+		 
+		self.writer.beginClass("ObjectManager", ["ObjectManagerBase"])
+
+		self.writer.beginConstructor()
+		self.writer.addFormalParameter("controller")
+		self.writer.beginMethodBody()
+		self.writer.beginSuperClassConstructorCall("ObjectManagerBase")
+		self.writer.addActualParameter("controller")
+		self.writer.endSuperClassConstructorCall()
+		self.writer.endMethodBody()
+		self.writer.endConstructor()
+
+		self.writer.beginMethod("instantiate")
+		self.writer.addFormalParameter("class_name")
+		self.writer.addFormalParameter("construct_params")
+		self.writer.beginMethodBody()
+		for index,c in enumerate(class_diagram.classes):
+			self.writer.beginElseIf(GLC.EqualsExpression("class_name", GLC.String(c.name)))
+			if c.isAbstract():
+				# cannot instantiate abstract class
+				self.writer.add(GLC.ThrowExceptionStatement(GLC.String("Cannot instantiate abstract class \"" + c.name + "\" with unimplemented methods \"" + "\", \"".join(c.abstract_method_names) + "\".")))
+			else:
+				new_expr = GLC.NewExpression(c.name, [GLC.SelfProperty("controller")])
+				param_count = 0
+				for p in c.constructors[0].parameters:
+					new_expr.getActualParameters().add(GLC.ArrayIndexedExpression("construct_params", str(param_count)))
+					param_count += 1
+				self.writer.addAssignment(
+					GLC.LocalVariableDeclaration("instance"),
+					new_expr)
+				self.writer.addAssignment(
+					GLC.Property("instance", "associations"),
+					GLC.MapExpression())
+				for a in c.associations:
+					a.accept(self)
+			self.writer.endElseIf()
+		self.writer.add(GLC.ReturnStatement("instance"))
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+		self.writer.endClass() # ObjectManager
+
+		if self.platform == Platforms.Threads:
+			controller_sub_class = "ThreadsControllerBase"
+		if self.platform == Platforms.EventLoop :
+			controller_sub_class = "EventLoopControllerBase"
+		elif self.platform == Platforms.GameLoop :
+			controller_sub_class = "GameLoopControllerBase"
+
+		self.writer.beginClass("Controller", [controller_sub_class])
+		self.writer.beginConstructor()
+		for p in class_diagram.default_class.constructors[0].parameters:
+			p.accept(self)
+		if self.platform == Platforms.EventLoop:
+			self.writer.addFormalParameter("event_loop_callbacks")
+			self.writer.addFormalParameter("finished_callback", GLC.NoneExpression())
+		elif self.platform == Platforms.Threads:
+			self.writer.addFormalParameter("keep_running", GLC.TrueExpression())
+		self.writer.beginMethodBody()
+		self.writer.beginSuperClassConstructorCall(controller_sub_class)
+		self.writer.addActualParameter(GLC.NewExpression("ObjectManager", [GLC.SelfExpression()]))
+		if self.platform == Platforms.EventLoop:
+			self.writer.addActualParameter("event_loop_callbacks")
+			self.writer.addActualParameter("finished_callback")
+		elif self.platform == Platforms.Threads:
+			self.writer.addActualParameter("keep_running")
+		self.writer.endSuperClassConstructorCall()
+		for i in class_diagram.inports:
+			self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addInputPort"), [GLC.String(i)]))
+		for o in class_diagram.outports:
+			self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addOutputPort"), [GLC.String(o)]))
+		actual_parameters = [p.getIdent() for p in class_diagram.default_class.constructors[0].parameters]
+		self.writer.add(GLC.FunctionCall(GLC.Property(GLC.SelfProperty("object_manager"), "createInstance"), [GLC.String(class_diagram.default_class.name), GLC.ArrayExpression(actual_parameters)]))
+		self.writer.endMethodBody()
+		self.writer.endConstructor()
+		self.writer.endClass() # Controller
+
+		# Visit test node if there is one
+		if class_diagram.test:
+			class_diagram.test.accept(self)
+
+		self.writer.endPackage()
+
+	def visit_DiagramTest(self, test):
+		# helper class
+		self.writer.beginClass("InputEvent")
+		self.writer.beginConstructor()
+		self.writer.addFormalParameter("name")
+		self.writer.addFormalParameter("port")
+		self.writer.addFormalParameter("parameters")
+		self.writer.addFormalParameter("time_offset")
+		self.writer.beginMethodBody()
+		self.writer.addAssignment(GLC.SelfProperty("name"), "name")
+		self.writer.addAssignment(GLC.SelfProperty("port"), "port")
+		self.writer.addAssignment(GLC.SelfProperty("parameters"), "parameters")
+		self.writer.addAssignment(GLC.SelfProperty("time_offset"), "time_offset")
+		self.writer.endMethodBody()
+		self.writer.endConstructor()
+		self.writer.endClass()
+		self.writer.beginClass("Test")
+		if test.input:
+			test.input.accept(self)
+		else:
+			self.writer.addStaticAttribute("input_events", GLC.ArrayExpression())
+		if test.expected:
+			test.expected.accept(self)
+		else:
+			self.writer.addStaticAttribute("expected_events", GLC.ArrayExpression())
+		self.writer.endClass()
+
+	def visit_DiagramTestInput(self, test_input):
+		# write array of input events
+		self.writer.startRecordingExpression()
+		self.writer.beginArray()
+		for e in test_input.input_events:
+			e.accept(self)
+		self.writer.endArray()
+		array_expr = self.writer.stopRecordingExpression()
+		self.writer.addStaticAttribute("input_events", array_expr)
+
+	def visit_DiagramTestInputEvent(self, event):
+		self.writer.add(GLC.NewExpression("InputEvent", [GLC.String(event.name), GLC.String(event.port), GLC.ArrayExpression(event.parameters), event.time]))
+
+	def visit_DiagramTestExpected(self, test_expected):
+		# write array of slots containing expected events
+		self.writer.startRecordingExpression()
+		self.writer.beginArray()
+		for s in test_expected.slots:
+			s.accept(self)
+		self.writer.endArray()
+		array_expr = self.writer.stopRecordingExpression()
+		self.writer.addStaticAttribute("expected_events", array_expr)
+
+	def visit_DiagramTestExpectedSlot(self, slot):
+		# write slot
+		self.writer.beginArray()
+		for e in slot.expected_events:
+			e.accept(self)
+		self.writer.endArray()
+
+	def visit_DiagramTestEvent(self, event):
+		self.writer.add(GLC.NewExpression("Event", [GLC.String(event.name), GLC.String(event.port), GLC.ArrayExpression(event.parameters)]))
+
+	def visit_Class(self, class_node):
+		"""
+		Generate code for Class construct
+		"""
+
+		super_classes = []
+		if not class_node.super_class_objs:
+			# if none of the class' super classes is defined in the diagram,
+			# we have to inherit RuntimeClassBase
+			if class_node.statechart:
+				# only inherit RuntimeClassBase if class has a statechart
+				super_classes.append("RuntimeClassBase")
+		if class_node.super_classes:
+			for super_class in class_node.super_classes:
+				super_classes.append(super_class)
+
+		self.writer.beginClass(class_node.name, super_classes)
+
+		#visit constructor
+		for i in class_node.constructors :
+			i.accept(self)
+
+		self.writer.beginMethod("user_defined_constructor")
+		for p in class_node.constructors[0].getParams():
+			p.accept(self)
+		self.writer.beginMethodBody()
+		for super_class in class_node.super_classes:
+			# begin call
+			if super_class in class_node.super_class_objs:
+				self.writer.beginSuperClassMethodCall(super_class, "user_defined_constructor")
+			else:
+				self.writer.beginSuperClassConstructorCall(super_class)
+			# write actual parameters
+			if super_class in class_node.constructors[0].super_class_parameters:
+				for p in class_node.constructors[0].super_class_parameters[super_class]:
+					self.writer.addActualParameter(p)
+			# end call
+			if super_class in class_node.super_class_objs:
+				self.writer.endSuperClassMethodCall()
+			else:
+				self.writer.endSuperClassConstructorCall()
+		self.writer.addRawCode(class_node.constructors[0].body)
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+
+
+		#visit children
+		for i in class_node.destructors :
+			i.accept(self)
+		for i in class_node.methods :
+			i.accept(self)
+
+		if class_node.statechart:
+			self.writer.beginMethod("initializeStatechart")
+			self.writer.beginMethodBody()
+
+			for c in class_node.statechart.composites :
+				self.writer.addAssignment(GLC.MapIndexedExpression(GLC.SelfProperty("current_state"), GLC.SelfProperty(c.full_name)), GLC.ArrayExpression())
+
+			if class_node.statechart.histories:
+				self.writer.addVSpace()
+				for node in class_node.statechart.combined_history_parents:
+					self.writer.addAssignment(GLC.MapIndexedExpression(GLC.SelfProperty("history_state"), GLC.SelfProperty(node.full_name)), GLC.ArrayExpression())
+
+			self.writer.addVSpace()
+			self.writer.addComment("Enter default state")	
+			for default_node in class_node.statechart.root.defaults:
+				if default_node.is_composite:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+default_node.full_name)))
+				elif default_node.is_basic:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+default_node.full_name)))
+			self.writer.endMethodBody()
+			self.writer.endMethod()
+
+			class_node.statechart.accept(self)
+
+		self.writer.endClass()
+
+
+	def visit_FormalParameter(self, formal_parameter):
+		self.writer.addFormalParameter(formal_parameter.getIdent(), formal_parameter.getDefault())
+		
+	def visit_Constructor(self, constructor):
+		self.writer.beginConstructor()
+		if constructor.parent_class.statechart:
+			self.writer.addFormalParameter("controller")
+		for p in constructor.getParams():
+			self.writer.addFormalParameter(p.getIdent(), p.getDefault())
+		self.writer.beginMethodBody() # constructor body
+
+		if constructor.parent_class.statechart:
+			self.writer.beginSuperClassConstructorCall("RuntimeClassBase")
+			self.writer.addActualParameter("controller")
+			self.writer.endSuperClassConstructorCall()
+
+			self.writer.addVSpace()
+
+			if constructor.parent_class.statechart.big_step_maximality == "take_one":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeOne"))
+			elif constructor.parent_class.statechart.big_step_maximality == "take_many":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "big_step_maximality"), GLC.Property("StatechartSemantics", "TakeMany"))
+
+			if constructor.parent_class.statechart.internal_event_lifeline == "queue":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "Queue"))
+			elif constructor.parent_class.statechart.internal_event_lifeline == "next_small_step":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextSmallStep"))
+			elif constructor.parent_class.statechart.internal_event_lifeline == "next_combo_step":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "internal_event_lifeline"), GLC.Property("StatechartSemantics", "NextComboStep"))
+
+			if constructor.parent_class.statechart.input_event_lifeline == "first_small_step":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstSmallStep"))
+			elif constructor.parent_class.statechart.input_event_lifeline == "first_combo_step":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "FirstComboStep"))
+			elif constructor.parent_class.statechart.input_event_lifeline == "whole":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "input_event_lifeline"), GLC.Property("StatechartSemantics", "Whole"))
+
+			if constructor.parent_class.statechart.priority == "source_parent":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceParent"))
+			elif constructor.parent_class.statechart.priority == "source_child":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "priority"), GLC.Property("StatechartSemantics", "SourceChild"))
+
+
+			if constructor.parent_class.statechart.concurrency == "single":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Single"))
+			elif constructor.parent_class.statechart.concurrency == "many":
+				self.writer.addAssignment(GLC.Property(GLC.SelfProperty("semantics"), "concurrency"), GLC.Property("StatechartSemantics", "Many"))
+
+		for p in constructor.parent_class.inports:
+			self.writer.addAssignment(
+				GLC.MapIndexedExpression(GLC.SelfProperty("inports"), GLC.String(p)),
+				GLC.FunctionCall(GLC.Property("controller", "addInputPort"), [GLC.String(p), GLC.SelfExpression()]))
+
+		if constructor.parent_class.attributes:
+			self.writer.addVSpace()
+			self.writer.addComment("User defined attributes")
+			for attribute in constructor.parent_class.attributes:
+				if attribute.init_value is None :
+					self.writer.addAssignment(GLC.SelfProperty(attribute.name), GLC.NoneExpression())
+				else :
+					self.writer.addAssignment(GLC.SelfProperty(attribute.name), attribute.init_value)
+
+		self.writer.addVSpace()
+		self.writer.addComment("Call user defined constructor")
+		self.writer.beginSuperClassMethodCall(constructor.parent_class.name, "user_defined_constructor")
+		for p in constructor.getParams():
+			# we can't do p.accept(self) here because 'p' is a FormalParameter
+			# and we want to write it as an actual parameter
+			self.writer.addActualParameter(p.getIdent())
+		self.writer.endSuperClassMethodCall()
+		self.writer.endMethodBody()
+		self.writer.endConstructor()
+
+	def visit_Destructor(self, destructor):
+		self.writer.beginMethod("user_defined_destructor")
+		self.writer.beginMethodBody()
+		if destructor.body.strip():
+			self.writer.addRawCode(destructor.body)
+		if destructor.parent_class.super_classes:
+			self.writer.addComment("Call super class destructors")
+			for super_class in destructor.parent_class.super_classes:
+				# begin call
+				if super_class in destructor.parent_class.super_class_objs:
+					self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
+					self.writer.endSuperClassMethodCall()
+				else:
+					self.writer.beginSuperClassDestructorCall(super_class)
+					self.writer.endSuperClassDestructorCall()
+					pass
+
+				#self.writer.beginSuperClassMethodCall(super_class, "user_defined_destructor")
+				#self.writer.endSuperClassMethodCall()
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+		
+	def visit_Method(self, method):
+		self.writer.addVSpace()
+		self.writer.beginMethod(method.name, "User defined method")
+		for p in method.parameters:
+			p.accept(self)
+		self.writer.beginMethodBody()
+		self.writer.addRawCode(method.body)
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+		
+	def visit_Association(self, association):
+		self.writer.addAssignment(
+			GLC.MapIndexedExpression(
+				GLC.Property("instance", "associations"),
+				GLC.String(association.name)),
+			GLC.NewExpression("Association", [GLC.String(association.to_class), str(association.min), str(association.max)]))
+
+	#helper method
+	def writeTransitionsRecursively(self, current_node):
+		valid_children = []
+		for child in current_node.children :
+			if child.is_composite or child.is_basic :
+				valid_children.append(child)
+
+		has_candidates_children = (len(valid_children) > 0)
+		has_candidates_current = (len(current_node.transitions) > 0)
+
+		if has_candidates_children:
+			self.writer.beginMethod("generateCandidatesChildren_" + current_node.full_name)
+			self.writer.beginMethodBody()
+			if current_node.is_parallel_state:
+				self.writer.addAssignment(
+					GLC.LocalVariableDeclaration("branch_done"),
+					GLC.FalseExpression())
+				for child in valid_children :
+					self.writer.addAssignment(
+						"branch_done",
+						GLC.OrExpression(
+							GLC.FunctionCall(GLC.SelfProperty("generateCandidates_" + child.full_name)),
+							"branch_done"))
+				self.writer.add(GLC.ReturnStatement("branch_done"))
+			elif current_node.is_composite:
+				for i, child in enumerate(valid_children) :
+					self.writer.beginElseIf(GLC.EqualsExpression(
+						GLC.ArrayIndexedExpression(
+							GLC.MapIndexedExpression(
+								GLC.SelfProperty("current_state"),
+								GLC.SelfProperty(current_node.full_name)),
+							"0"),
+						GLC.SelfProperty(child.full_name)))
+					self.writer.add(GLC.ReturnStatement(GLC.FunctionCall(GLC.SelfProperty("generateCandidates_"+child.full_name))))
+					self.writer.endElseIf()
+				self.writer.add(GLC.ReturnStatement(GLC.FalseExpression()))
+			self.writer.endMethodBody()
+			self.writer.endMethod()
+
+		if has_candidates_current:
+			self.writer.beginMethod("generateCandidatesCurrent_" + current_node.full_name)
+			self.writer.beginMethodBody()
+			self.writeFromTransitions(current_node)
+			self.writer.add(GLC.ReturnStatement(GLC.FalseExpression()))
+			self.writer.endMethodBody()
+			self.writer.endMethod()
+
+		self.writer.beginMethod("generateCandidates_" + current_node.full_name)
+		self.writer.beginMethodBody()
+
+		if not has_candidates_children and not has_candidates_current:
+			self.writer.add(GLC.ReturnStatement(GLC.FalseExpression()))
+		else:
+			self.writer.beginIf(
+				GLC.NotExpression(GLC.FunctionCall(
+					GLC.Property(GLC.SelfProperty("combo_step"), "isArenaChanged"),
+					[GLC.SelfProperty(current_node.full_name)])))
+
+			if has_candidates_children and has_candidates_current:
+				self.writer.addAssignment(
+					GLC.LocalVariableDeclaration("branch_done"),
+					GLC.FalseExpression())
+
+			if not has_candidates_children and has_candidates_current:
+				self.writer.add(GLC.ReturnStatement(GLC.FunctionCall(GLC.SelfProperty("generateCandidatesCurrent_" + current_node.full_name))))
+			elif not has_candidates_current and has_candidates_children:
+				self.writer.add(GLC.ReturnStatement(GLC.FunctionCall(GLC.SelfProperty("generateCandidatesChildren_" + current_node.full_name))))
+			else:
+				self.writer.beginElseIf(GLC.EqualsExpression(
+					GLC.Property(GLC.SelfProperty("semantics"), "priority"),
+					GLC.Property("StatechartSemantics", "SourceParent")))
+				if has_candidates_current:
+					self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesCurrent_" + current_node.full_name)))
+				if has_candidates_children:
+					self.writer.beginIf(GLC.NotExpression("branch_done"))
+					self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesChildren_" + current_node.full_name)))
+					self.writer.endIf()
+				self.writer.endElseIf()
+				self.writer.beginElseIf(GLC.EqualsExpression(
+					GLC.Property(GLC.SelfProperty("semantics"), "priority"),
+					GLC.Property("StatechartSemantics", "SourceChild")))
+				if has_candidates_children:
+					self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesChildren_" + current_node.full_name)))
+				if has_candidates_current:
+					self.writer.beginIf(GLC.NotExpression("branch_done"))
+					self.writer.addAssignment("branch_done", GLC.FunctionCall(GLC.SelfProperty("generateCandidatesCurrent_" + current_node.full_name)))
+					self.writer.endIf()
+				self.writer.endElseIf()
+
+			if has_candidates_children and has_candidates_current:
+				self.writer.add(GLC.ReturnStatement("branch_done"))
+			self.writer.endIf()
+			self.writer.beginElse()
+			self.writer.add(GLC.ReturnStatement(GLC.TrueExpression()))
+			self.writer.endElse()
+
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+
+		for index, transition in enumerate(current_node.transitions, start=1):
+			self.writeTransitionAction(transition, index)
+		
+		for child in valid_children :
+			self.writeTransitionsRecursively(child)
+				
+	#helper method
+	def writeFromTransitions(self, current_node): 
+		# get all transition out of this state
+		out_transitions = current_node.transitions
+		if len(out_transitions) == 0 :
+			return
+		
+		for index, transition in enumerate(out_transitions, start=1):
+			self.writeTransitionCondition(transition, index)
+		
+	def visit_FormalEventParameter(self, formal_event_parameter):
+		self.writer.add(formal_event_parameter.name)
+		
+	def writeFormalEventParameters(self, transition):
+		parameters = transition.getTrigger().getParameters()
+		if(len(parameters) > 0) :
+			for index, parameter in enumerate(parameters):
+				self.writer.startRecordingExpression()
+				parameter.accept(self)
+				parameter_expr = self.writer.stopRecordingExpression()
+				self.writer.addAssignment(
+					GLC.LocalVariableDeclaration(parameter_expr),
+					GLC.ArrayIndexedExpression("parameters", str(index)))
+		
+		
+	def writeTransitionAction(self, transition, index):
+		self.writer.beginMethod("transition_" + transition.parent_node.full_name + "_" + str(index))
+		self.writer.addFormalParameter("parameters")
+		self.writer.beginMethodBody()
+
+		# handle parameters to actually use them
+		self.writeFormalEventParameters(transition)
+		
+		exits = transition.getExitNodes()
+		
+		# write exit actions
+		if not exits[-1].is_basic:
+			self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+exits[-1].full_name)))
+		else:
+			for node in exits:
+				if node.is_basic:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+node.full_name)))
+					
+		# write trigger actions
+		transition.getAction().accept(self)
+
+		# add arena of transition to list of 'changed' states,
+		# this may prevent other transitions whose arenas overlap to be taken
+		self.writer.add(
+			GLC.FunctionCall(
+				GLC.Property(GLC.SelfProperty("combo_step"), "setArenaChanged"),
+				[GLC.SelfProperty(transition.arena.full_name)]))
+
+		# write enter actions
+		for (entering_node, is_ending_node) in transition.getEnterNodes() : 
+			if is_ending_node :
+				if entering_node.is_composite:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + entering_node.full_name)))
+				elif entering_node.is_history:
+					if (entering_node.is_history_deep) :
+						self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_" + entering_node.parent.full_name)))
+					else :
+						self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryShallow_" + entering_node.parent.full_name)))
+				else:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + entering_node.full_name)))
+			else :
+				if entering_node.is_composite:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + entering_node.full_name)))
+
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+						
+	def writeTransitionCondition(self, transition, index):
+		trigger = transition.getTrigger()
+
+		self.writer.addAssignment(
+			GLC.LocalVariableDeclaration("enabled_events"),
+			GLC.FunctionCall(GLC.SelfProperty("getEnabledEvents")))
+
+		if not trigger.isUC():
+			self.writer.beginForLoopIterateArray("enabled_events", "e")
+			condition = GLC.EqualsExpression(
+				GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "name"),
+					GLC.String(trigger.getEvent()))
+			if trigger.getPort() != "":
+				condition = GLC.AndExpression(
+					condition,
+					GLC.EqualsExpression(
+						GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "port"),
+						GLC.String(trigger.getPort())))
+			self.writer.beginIf(condition)
+		# evaluate guard
+		if transition.hasGuard() :
+			# handle parameters for guard evaluation
+			if not transition.getTrigger().isUC():
+				self.writer.addAssignment(GLC.LocalVariableDeclaration("parameters"), GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "parameters"))
+				self.writeFormalEventParameters(transition)
+			self.writer.startRecordingExpression()
+			transition.getGuard().accept(self) # --> visit_Expression
+			expr = self.writer.stopRecordingExpression()
+			self.writer.beginIf(expr)
+
+		if trigger.isUC():
+			params_expr = GLC.ArrayExpression()
+		else:
+			params_expr = GLC.Property(GLC.ForLoopCurrentElement("enabled_events", "e"), "parameters")
+		self.writer.add(GLC.FunctionCall(GLC.Property(GLC.SelfProperty("small_step"), "addCandidate"), [GLC.SelfProperty("transition_" + transition.parent_node.full_name + "_" + str(index)), params_expr]))
+
+		self.writer.add(GLC.ReturnStatement(GLC.TrueExpression()))
+
+		if transition.hasGuard() :
+			self.writer.endIf()
+		if not trigger.isUC() :
+			self.writer.endIf()
+			self.writer.endForLoopIterateArray()
+	
+	def visit_EnterAction(self, enter_method):
+		parent_node = enter_method.parent_node
+		self.writer.beginMethod("enter_" + parent_node.full_name)
+		self.writer.beginMethodBody()
+
+		# take care of any AFTER events
+		for transition in parent_node.transitions :
+			trigger = transition.getTrigger()
+			if trigger.isAfter() :
+				self.writer.startRecordingExpression()
+				trigger.after.accept(self)
+				after = self.writer.stopRecordingExpression()
+				
+				self.writer.addAssignment(
+					GLC.MapIndexedExpression(GLC.SelfProperty("timers"), str(trigger.getAfterIndex())),
+					after)
+
+		if enter_method.action:
+			enter_method.action.accept(self)
+		self.writer.add(
+			GLC.ArrayPushBack(
+					GLC.MapIndexedExpression(
+						GLC.SelfProperty("current_state"),
+						GLC.SelfProperty(parent_node.parent.full_name)),
+					GLC.SelfProperty(parent_node.full_name)))
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+		
+	#helper method
+	def writeEnterDefault(self, entered_node):
+		self.writer.beginMethod("enterDefault_" + entered_node.full_name)
+		self.writer.beginMethodBody()
+		self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+entered_node.full_name)))
+		if entered_node.is_composite:
+			l = entered_node.defaults
+			for i in l:
+				if i.is_composite:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_" + i.full_name)))
+				elif i.is_basic:
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_" + i.full_name)))
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+		 
+	def visit_ExitAction(self, exit_method):
+		exited_node = exit_method.parent_node
+		self.writer.beginMethod("exit_" + exited_node.full_name)
+		self.writer.beginMethodBody()
+
+		#If the exited node is composite take care of potential history and the leaving of descendants
+		if exited_node.is_composite :
+			#handle history
+			if exited_node.save_state_on_exit :
+				self.writer.addAssignment(
+					GLC.MapIndexedExpression(
+						GLC.SelfProperty("history_state"),
+						GLC.SelfProperty(exited_node.full_name)),
+					GLC.MapIndexedExpression(
+						GLC.SelfProperty("current_state"),
+						GLC.SelfProperty(exited_node.full_name)))
+			
+			#Take care of leaving children
+			children = exited_node.children
+			if exited_node.is_parallel_state:
+				for child in children:
+					if not child.is_history :
+						self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+child.full_name)))
+			else:
+				for child in children:
+					if not child.is_history :
+						self.writer.beginIf(GLC.ArrayContains(
+								GLC.MapIndexedExpression(
+									GLC.SelfProperty("current_state"),
+									GLC.SelfProperty(exited_node.full_name)),
+								GLC.SelfProperty(child.full_name)))
+						self.writer.add(GLC.FunctionCall(GLC.SelfProperty("exit_"+child.full_name)))
+						self.writer.endIf()
+		
+		# take care of any AFTER events
+		for transition in exited_node.transitions :
+			trigger = transition.getTrigger()
+			if trigger.isAfter() :
+				self.writer.add(GLC.MapRemoveElement(
+					GLC.SelfProperty("timers"),
+					str(trigger.getAfterIndex())))
+				
+		#Execute user-defined exit action if present
+		if exit_method.action:
+			exit_method.action.accept(self)
+			
+		#Adjust state
+		self.writer.addAssignment(
+			GLC.MapIndexedExpression(
+				GLC.SelfProperty("current_state"),
+				GLC.SelfProperty(exited_node.parent.full_name)),
+			GLC.ArrayExpression()) # SPECIAL CASE FOR ORTHOGONAL??
+		
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+		
+			
+	#helper method
+	def writeEnterHistory(self, entered_node, is_deep):
+		self.writer.beginMethod("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name)
+		self.writer.beginMethodBody()
+
+		self.writer.beginIf(GLC.EqualsExpression(
+			GLC.ArrayLength(
+				GLC.MapIndexedExpression(
+					GLC.SelfProperty("history_state"),
+					GLC.SelfProperty(entered_node.full_name))),
+			"0"))
+		"""self.writer.beginIfBlock(GLC.EqualsExpression(
+			GLC.ArrayLength(
+				GLC.MapIndexedExpression(
+					GLC.SelfProperty("history_state"),
+					GLC.SelfProperty(entered_node.full_name))),
+			"0"))"""
+		defaults = entered_node.defaults
+
+		for node in defaults:
+			if node.is_basic :
+				self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+node.full_name)))
+			elif node.is_composite :
+				self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+node.full_name)))
+
+		self.writer.endIf()
+		self.writer.beginElse()
+		children = entered_node.children
+		if entered_node.is_parallel_state:
+			for child in children:
+				if not child.is_history :
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
+					self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistory"+("Deep" if is_deep else "Shallow")+"_"+child.full_name)))
+		else:
+			for child in children:
+				if not child.is_history :
+					self.writer.beginIf(GLC.ArrayContains(
+						GLC.MapIndexedExpression(
+							GLC.SelfProperty("history_state"),
+							GLC.SelfProperty(entered_node.full_name)),
+						GLC.SelfProperty(child.full_name)))
+					if child.is_composite:
+						if is_deep :
+							self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
+							self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterHistoryDeep_"+child.full_name)))
+						else :
+							self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enterDefault_"+child.full_name)))
+					else:
+						self.writer.add(GLC.FunctionCall(GLC.SelfProperty("enter_"+child.full_name)))
+					self.writer.endIf()
+		self.writer.endElse()
+
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+
+	def visit_StateChart(self, statechart):
+
+		# assign each node a unique ID
+		self.writer.addVSpace()
+		self.writer.addComment("Unique IDs for all statechart nodes")
+		for (i,node) in enumerate(statechart.composites + statechart.basics):
+			self.writer.addStaticAttribute(node.full_name, str(i))
+
+
+
+		self.writer.addVSpace()
+		self.writer.addComment("Statechart enter/exit action method(s)")
+		
+		#visit enter and exit action of children
+		for i in statechart.composites + statechart.basics:
+			if i is not statechart.root :
+				i.enter_action.accept(self)
+				i.exit_action.accept(self)
+
+		# write out statecharts methods for enter/exit state
+		if len(statechart.composites) > 1 :
+			self.writer.addVSpace()
+			self.writer.addComment("Statechart enter/exit default method(s)")
+			for i in statechart.composites :
+				if i is not statechart.root :
+					self.writeEnterDefault(i)
+
+		# write out statecharts methods for enter/exit history
+		if statechart.histories:
+			self.writer.addVSpace()
+			self.writer.addComment("Statechart enter/exit history method(s)")
+			for i in statechart.shallow_history_parents:
+				self.writeEnterHistory(i, False)
+			for i in statechart.deep_history_parents:
+				self.writeEnterHistory(i, True) 
+
+		self.writer.addVSpace()
+		self.writer.addComment("Statechart transitions")
+		self.writeTransitionsRecursively(statechart.root)			
+				
+		# write out transition function
+		self.writer.beginMethod("generateCandidates", "Generate transition candidates for current small step")
+		self.writer.beginMethodBody()
+		self.writer.add(GLC.FunctionCall(
+				GLC.SelfProperty("generateCandidates_"+statechart.root.full_name)))
+		self.writer.endMethodBody()
+		self.writer.endMethod()
+
+	def visit_SelfReference(self, self_reference):
+		self.writer.add(GLC.SelfExpression())
+
+	def visit_StateReference(self, state_ref):
+		self.writer.beginArray()
+		for node in state_ref.getNodes():
+			self.writer.add(GLC.SelfProperty(node.full_name))
+		self.writer.endArray()
+
+	def visit_InStateCall(self, in_state_call):
+		self.writer.beginFunctionCall(GLC.SelfProperty("inState"))
+		self.writer.startRecordingExpression()
+		in_state_call.target.accept(self)
+		expr = self.writer.stopRecordingExpression()
+		self.writer.addActualParameter(expr)
+		self.writer.endFunctionCall()
+
+	def visit_Expression(self, expression):
+		self.writer.startRecordingExpression()
+		self.writer.beginGlue()
+		for part in expression.expression_parts:
+			part.accept(self)
+		self.writer.endGlue()
+		expr = self.writer.stopRecordingExpression()
+		self.writer.add(expr)
+
+	def visit_ExpressionPartString(self, e):
+		self.writer.add(e.string)
+		
+	def visit_RaiseEvent(self, raise_event):
+		self.writer.startRecordingExpression()
+		self.writer.begin(GLC.NewExpression("Event"))
+
+		self.writer.addActualParameter(GLC.String(raise_event.getEventName()))
+		if raise_event.isOutput():
+			self.writer.addActualParameter(GLC.String(raise_event.getPort()))
+		else:
+			self.writer.addActualParameter(GLC.NoneExpression())
+
+		self.writer.end()
+		new_event_expr = self.writer.stopRecordingExpression()
+
+		self.writer.startRecordingExpression()
+		self.writer.beginArray()
+		if raise_event.isCD():
+			self.writer.add(GLC.SelfExpression())
+		for param in raise_event.getParameters() :
+			param.accept(self) # -> visit_Expression will cause expressions to be added to array
+		self.writer.endArray()
+		parameters_array_expr = self.writer.stopRecordingExpression()
+		new_event_expr.getActualParameters().add(parameters_array_expr)
+
+		if raise_event.isNarrow():
+			self.writer.add(GLC.FunctionCall(
+				GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"), [
+					GLC.NewExpression("Event", [
+						GLC.String("narrow_cast"),
+						GLC.NoneExpression(),
+						GLC.ArrayExpression([
+							GLC.SelfExpression(),
+							raise_event.getTarget(),
+							new_event_expr])])]))
+		elif raise_event.isLocal():
+			self.writer.add(GLC.FunctionCall(
+				GLC.SelfProperty("raiseInternalEvent"),
+				[new_event_expr]))
+		elif raise_event.isOutput():
+			self.writer.add(GLC.FunctionCall(
+				GLC.Property(GLC.SelfProperty("big_step"), "outputEvent"),
+				[new_event_expr]))
+		elif raise_event.isCD():
+			self.writer.add(GLC.FunctionCall(
+				GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"),
+				[new_event_expr]))
+		elif raise_event.isBroad():
+			self.writer.add(GLC.FunctionCall(
+				GLC.Property(GLC.SelfProperty("big_step"), "outputEventOM"),
+				[GLC.NewExpression("Event", [
+					GLC.String("broad_cast"),
+					GLC.NoneExpression(),
+					GLC.ArrayExpression([
+						new_event_expr])])]))
+			
+	def visit_Script(self, script):
+		self.writer.addRawCode(script.code)
+		
+	def visit_Log(self, log):
+		self.writer.add(GLC.LogStatement(log.message))
+		
+	def visit_Assign(self, assign):
+		self.writer.startRecordingExpression()
+		assign.lvalue.accept(self) # --> visit_Expression
+		lvalue = self.writer.stopRecordingExpression()
+		self.writer.startRecordingExpression()
+		assign.expression.accept(self) # --> visit_Expression
+		rvalue = self.writer.stopRecordingExpression()
+		self.writer.addAssignment(lvalue, rvalue)
+

+ 990 - 0
hybrid_server/python_sccd_compiler/generic_language_constructs.py

@@ -0,0 +1,990 @@
+import abc
+from visitor import Visitor, Visitable
+
+
+class GenericConstruct(Visitable):
+	__metaclass__ = abc.ABCMeta
+
+
+# base class for constructs that are a collection of other constructs
+class AbstractList:
+	__metaclass__ = abc.ABCMeta
+
+	@abc.abstractmethod
+	def add(self, generic_construct):
+		pass
+
+
+class BlockEntry(GenericConstruct):
+	__metaclass__ = abc.ABCMeta
+
+	@abc.abstractmethod
+	def isEmpty(self):
+		pass
+
+
+class DeclarationBase:
+	def __init__(self, identifier, description = None):
+		self.identifier = identifier
+		self.description = description # string describing declared artifact
+
+	def getIdentifier(self):
+		return self.identifier
+
+	def getDescription(self):
+		return self.description
+
+
+class Statement(BlockEntry):
+	pass
+
+
+class Package(Statement, AbstractList, DeclarationBase):
+	def __init__(self, identifier, description = None):
+		DeclarationBase.__init__(self, identifier, description)
+		self.declarations = []
+
+	def add(self, item):
+		self.declarations.append(MakeDeclaration(item))
+
+	def getDeclarations(self):
+		return self.declarations
+
+	def isEmpty(self):
+		return False
+
+
+class FormalParameters(GenericConstruct, AbstractList):
+	def __init__(self, parameter_list = None):
+		if parameter_list is None: parameter_list = []
+		self.parameter_list = parameter_list
+
+	def add(self, parameter):
+		self.parameter_list.append(parameter)
+
+	def getParameterList(self):
+		return self.parameter_list
+
+class AST(GenericConstruct, AbstractList):
+	def __init__(self):
+		self.entries = []
+
+	def add(self, entry):
+		self.entries.append(MakeBlockEntry(entry))
+
+	def getEntries(self):
+		return self.entries
+
+
+class Block(AST):
+	def __init__(self):
+		AST.__init__(self)
+
+	def isEmpty(self):
+		for e in self.getEntries():
+			if not e.isEmpty():
+				return False
+		return True
+
+
+class ForLoopBody(Block):
+	def __init__(self, for_loop):
+		Block.__init__(self)
+		self.for_loop = for_loop
+
+	def getForLoop(self):
+		return self.for_loop
+
+
+class MethodBody(Block):
+	def __init__(self, method):
+		Block.__init__(self)
+		self.method = method
+
+	def getMethod(self):
+		return self.method
+
+
+#class ConstructorBody(MethodBody):
+#	def __init__(self, method):
+#		MethodBody.__init__(self, method)
+
+#class DestructorBody(MethodBody):
+#	def __init__(self, method):
+#		MethodBody.__init__(self, method)
+
+
+class ClassMember(GenericConstruct, DeclarationBase):
+	def __init__(self, c, identifier, description = None):
+		DeclarationBase.__init__(self, identifier, description)
+		self.c = c # Class
+
+	def getClass(self):
+		return self.c
+
+
+class MethodBase(ClassMember):
+	def __init__(self, c, identifier, description = None):
+		ClassMember.__init__(self, c, identifier, description)
+		self.formal_parameters = FormalParameters()
+		self.body = MethodBody(self)
+
+	def getBody(self):
+		return self.body
+
+	def getFormalParameters(self):
+		return self.formal_parameters
+
+
+class Method(MethodBase):
+	def __init__(self, c, identifier, description = None):
+		MethodBase.__init__(self, c, identifier, description)
+
+
+class Constructor(MethodBase):
+	def __init__(self, c, description = None):
+		MethodBase.__init__(self, c, None, description)
+
+
+class Destructor(MethodBase):
+	def __init__(self, c, description = None):
+		MethodBase.__init__(self, c, None, description)
+
+
+class Class(GenericConstruct, AbstractList, DeclarationBase):
+	def __init__(self, identifier, super_class_identifier_list = None, description = None):
+		DeclarationBase.__init__(self, identifier, description)
+		self.super_class_identifier_list = super_class_identifier_list # string
+		self.constructor = Constructor(self)
+		self.destructor = Destructor(self)
+		self.members = []
+
+	def getSuperClassIdentifierList(self):
+		return self.super_class_identifier_list
+
+	def getConstructor(self):
+		return self.constructor
+
+	def getDestructor(self):
+		return self.destructor
+
+	def add(self, class_member):
+		self.members.append(class_member)
+
+	def getMembers(self):
+		return self.members
+
+
+class AttributeBase(ClassMember):
+	def __init__(self, c, identifier, init_value = None):
+		ClassMember.__init__(self, c, identifier)
+		self.init_value = MakeExpression(init_value)
+
+	def getInitValue(self):
+		return self.init_value
+
+
+class Attribute(AttributeBase):
+	def __init__(self, c, identifier, init_value = None):
+		AttributeBase.__init__(self, c, identifier, init_value)
+
+
+class StaticAttribute(AttributeBase):
+	def __init__(self, c, name, init_value = None):
+		AttributeBase.__init__(self, c, name, init_value)
+
+
+class FormalParameter(GenericConstruct, DeclarationBase):
+	def __init__(self, identifier, default_value = None, description = None):
+		DeclarationBase.__init__(self, identifier, description)
+		#self.identifier = identifier
+		self.default_value = MakeExpression(default_value)
+
+	def getDefaultValue(self):
+		return self.default_value
+
+
+class IncludeStatement(Statement):
+	def __init__(self, module_path, imported_symbols = None):
+		if imported_symbols is None: imported_symbols = []
+		self.module_path = MakeExpressionList(module_path) # list of modules
+		self.imported_symbols = imported_symbols
+
+	def getModulePath(self):
+		return self.module_path
+
+	def getImportedSymbols(self):
+		return self.imported_symbols
+
+	def isEmpty(self):
+		return False
+
+
+class ReturnStatement(Statement):
+	def __init__(self, expr):
+		self.expr = MakeExpression(expr)
+
+	def getExpression(self):
+		return self.expr
+
+	def isEmpty(self):
+		return False
+
+class BreakStatement(Statement):
+	def isEmpty(self):
+		return False	
+
+class ThrowExceptionStatement(Statement):
+	def __init__(self, expr):
+		self.expr = MakeExpression(expr)
+
+	def getExpression(self):
+		return self.expr
+
+	def isEmpty(self):
+		return False
+
+
+class VSpace(BlockEntry):
+	def isEmpty(self):
+		return True
+
+
+class CommentBase(BlockEntry):
+	def __init__(self, text):
+		self.text = text
+
+	def isEmpty(self):
+		return True
+
+	def getText(self):
+		return self.text
+
+
+class SingleLineComment(CommentBase):
+	def __init__(self, text):
+		CommentBase.__init__(self,text)
+
+
+class MultiLineComment(CommentBase):
+	def __init__(self, text):
+		CommentBase.__init__(self,text)
+
+
+class ConditionalStatementBase(Statement, AbstractList):
+	def __init__(self, body = None):
+		if body is None: body = Block()
+		self.body = body
+
+	def add(self, stmt):
+		self.body.add(stmt)
+
+	def getBody(self):
+		return self.body
+
+	def isEmpty(self):
+		return False
+
+
+class IfStatement(ConditionalStatementBase):
+	def __init__(self, condition):
+		ConditionalStatementBase.__init__(self)
+		self.condition = MakeExpression(condition)
+
+	def getCondition(self):
+		return self.condition
+
+
+class ElseStatement(ConditionalStatementBase):
+	def __init__(self):
+		ConditionalStatementBase.__init__(self)
+
+
+class ElseIfStatement(IfStatement):
+	def __init__(self, condition, is_first = False):
+		IfStatement.__init__(self, condition)
+		self.is_first = is_first
+
+	# in a series of ElseIfStatements, the first ElseIfStatement will be a normal if statement
+	def isFirst(self):
+		return self.is_first
+
+
+class ForLoopIterateBase(ConditionalStatementBase):
+	def __init__(self, collection_expr, iterator_identifier):
+		ConditionalStatementBase.__init__(self, ForLoopBody(self))
+		self.collection_expr = MakeExpression(collection_expr)
+		self.iterator_identifier = iterator_identifier
+
+	def getCollectionExpression(self):
+		return self.collection_expr
+
+	def getIteratorIdentifier(self):
+		return self.iterator_identifier
+
+
+class ForLoopIterateArray(ForLoopIterateBase):
+	def __init__(self, array_expr, iterator_identifier):
+		ForLoopIterateBase.__init__(self, array_expr, iterator_identifier)
+
+
+class ForLoopIterateMapValues(ForLoopIterateBase):
+	def __init__(self, map_expr, iterator_identifier):
+		ForLoopIterateBase.__init__(self, map_expr, iterator_identifier)
+
+
+class ExpressionStatement(Statement):
+	def __init__(self, expression):
+		self.expression = expression
+
+	def getExpression(self):
+		return self.expression
+
+	def isEmpty(self):
+		return False
+
+
+# block of raw code
+class RawCode(BlockEntry):
+	def __init__(self, text):
+		self.text = text
+
+	def getText(self):
+		return self.text
+
+	def isEmpty(self):
+		return (len(self.text.strip()) == 0)
+
+
+# log message to console
+class LogStatement(Statement):
+	def __init__(self, msg):
+		self.msg = msg
+
+	def getMessage(self):
+		return self.msg
+
+	def isEmpty(self):
+		return False
+
+
+class Expression(GenericConstruct):
+	__metaclass__ = abc.ABCMeta
+
+	@abc.abstractmethod
+	def isCompound(self):
+		pass
+
+class SimpleExpression(Expression):
+	def isCompound(self):
+		return False
+
+class CompoundExpression(Expression):
+	def isCompound(self):
+		return True
+
+class RuntimeModuleIdentifier(SimpleExpression):
+	pass
+
+# Not a real language construct, simply 'glues' expressions together.
+class Glue(SimpleExpression, AbstractList):
+	def __init__(self):
+		self.expression_list = []
+
+	def add(self, expr):
+		self.expression_list.append(MakeExpression(expr))
+
+	def getExpressionList(self):
+		return self.expression_list
+
+
+class ForLoopCurrentElement(SimpleExpression):
+	def __init__(self, collection_expr, iterator_identifier):
+		self.collection_expr = MakeExpression(collection_expr)
+		self.iterator_identifier = iterator_identifier
+
+	def getCollectionExpression(self):
+		return self.collection_expr
+
+	def getIteratorIdentifier(self):
+		return self.iterator_identifier
+
+
+class Literal(SimpleExpression):
+	def __init__(self, text):
+		self.text = text
+
+	def getText(self):
+		return self.text
+
+
+class String(Literal):
+	def __init__(self, text):
+		Literal.__init__(self, text)
+
+
+class Property(SimpleExpression):
+	def __init__(self, owner, prop):
+		self.owner = MakeExpression(owner)
+		self.prop = prop
+
+	def getOwnerExpression(self):
+		return self.owner
+
+	def getProperty(self):
+		return self.prop
+
+
+class MapIndexedExpression(SimpleExpression):
+	def __init__(self, map_expr, key_expr):
+		self.map_expr = MakeExpression(map_expr)
+		self.key_expr = MakeExpression(key_expr)
+
+	def getMapExpression(self):
+		return self.map_expr
+
+	def getKeyExpression(self):
+		return self.key_expr
+
+
+class ArrayIndexedExpression(SimpleExpression):
+	def __init__(self, array_expr, index_expr):
+		self.array_expr = MakeExpression(array_expr)
+		self.index_expr = MakeExpression(index_expr)
+
+	def getArrayExpression(self):
+		return self.array_expr
+
+	def getIndexExpression(self):
+		return self.index_expr
+
+
+class ActualParameters(GenericConstruct, AbstractList):
+	def __init__(self, parameter_list = None):
+		if parameter_list is None: parameter_list = []
+		self.parameter_list = MakeExpressionList(parameter_list)
+
+	def add(self, p):
+		self.parameter_list.append(MakeExpression(p))
+		pass
+
+	def getParameterList(self):
+		return self.parameter_list
+
+
+class FunctionCallBase(SimpleExpression):
+	def __init__(self, actual_parameters = None):
+		if actual_parameters is None: actual_parameters = ActualParameters()
+		self.actual_parameters = MakeActualParameters(actual_parameters)
+
+	def getActualParameters(self):
+		return self.actual_parameters
+	
+
+
+class FunctionCall(FunctionCallBase):
+	def __init__(self, function_expr, actual_parameters = None):
+		FunctionCallBase.__init__(self, actual_parameters)
+		self.function_expr = MakeExpression(function_expr)
+
+	def getFunctionExpression(self):
+		return self.function_expr
+
+
+class SuperClassCallBase(FunctionCallBase):
+	def __init__(self, super_class_identifier, actual_parameters = None):
+		FunctionCallBase.__init__(self, actual_parameters)
+		self.super_class_identifier = super_class_identifier
+
+	def getSuperClassIdentifier(self):
+		return self.super_class_identifier
+
+
+class SuperClassConstructorCall(SuperClassCallBase):
+	def __init__(self, super_class_identifier, actual_parameters = None):
+		SuperClassCallBase.__init__(self, super_class_identifier, actual_parameters)
+
+
+class SuperClassDestructorCall(SuperClassCallBase):
+	def __init__(self, super_class_identifier):
+		SuperClassCallBase.__init__(self, super_class_identifier)
+
+
+class SuperClassMethodCall(SuperClassCallBase):
+	def __init__(self, super_class_identifier, method_identifier, actual_parameters = None):
+		SuperClassCallBase.__init__(self, super_class_identifier, actual_parameters)
+		self.method_identifier = method_identifier
+
+	def getMethodIdentifier(self):
+		return self.method_identifier
+
+
+class NewExpression(FunctionCallBase):
+	def __init__(self, type_expr, actual_parameters = None):
+		FunctionCallBase.__init__(self, actual_parameters)
+		self.type_expr = MakeExpression(type_expr)
+
+	def getTypeExpression(self):
+		return self.type_expr
+
+
+class SelfExpression(SimpleExpression):
+	pass
+
+
+class SelfProperty(Property):
+	def __init__(self, prop):
+		Property.__init__(self, SelfExpression(), prop)
+
+
+class Operator(GenericConstruct):
+	pass
+
+
+class AndOperator(Operator):
+	pass
+
+class OrOperator(Operator):
+	pass
+
+class LessThanOperator(Operator):
+	pass
+
+class GreaterThanOperator(Operator):
+	pass
+
+class NotOperator(Operator):
+	pass
+
+class EqualsOperator(Operator):
+	pass
+
+class AssignmentOperator(Operator):
+	pass
+
+class ProductOperator(Operator):
+	pass
+
+
+class UnaryExpression(CompoundExpression):
+	def __init__(self, operator, expr):
+		self.operator = operator
+		self.expr = MakeExpression(expr)
+
+	def getExpression(self):
+		return self.expr
+
+	def getOperator(self):
+		return self.operator
+
+
+class BinaryExpression(CompoundExpression):
+	def __init__(self, lhs_expr, operator, rhs_expr):
+		self.lhs_expr = MakeExpression(lhs_expr)
+		self.operator = operator
+		self.rhs_expr = MakeExpression(rhs_expr)
+
+	def getLhsExpression(self):
+		return self.lhs_expr
+
+	def getRhsExpression(self):
+		return self.rhs_expr
+
+	def getOperator(self):
+		return self.operator
+
+
+class NotExpression(UnaryExpression):
+	def __init__(self, expr):
+		UnaryExpression.__init__(self, NotOperator(), expr)
+
+class AndExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, AndOperator(), rexpr)
+
+class OrExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, OrOperator(), rexpr)
+
+class LessThanExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, LessThanOperator(), rexpr)
+
+class GreaterThanExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, GreaterThanOperator(), rexpr)
+
+class EqualsExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, EqualsOperator(), rexpr)
+
+class AssignmentExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, AssignmentOperator(), rexpr)
+
+class ProductExpression(BinaryExpression):
+	def __init__(self, lexpr = None, rexpr = None):
+		BinaryExpression.__init__(self, lexpr, ProductOperator(), rexpr)
+
+
+class FalseExpression(SimpleExpression):
+	pass
+
+class TrueExpression(SimpleExpression):
+	pass
+
+
+class LocalVariableDeclaration(Expression, DeclarationBase):
+	def __init__(self, identifier, init_value = None, description = None):
+		DeclarationBase.__init__(self, identifier, description)
+		self.init_value = MakeExpression(init_value)
+
+	def getInitValue(self):
+		self.init_value
+
+	def isCompound(self):
+		return (self.init_value != None)
+
+
+class MapExpression(SimpleExpression):
+	def __init__(self, elements = None):
+		if elements is None: elements = {}
+		self.elements = MakeExpressionMap(elements)
+
+	def getElements(self):
+		return self.elements
+
+class MapRemoveElement(Statement):
+	def __init__(self, map_expr, key_expr):
+		self.map_expr = MakeExpression(map_expr)
+		self.key_expr = MakeExpression(key_expr)
+
+	def getMapExpression(self):
+		return self.map_expr
+
+	def getKeyExpression(self):
+		return self.key_expr
+
+	def isEmpty(self):
+		return False
+
+
+class ArrayExpression(SimpleExpression, AbstractList):
+	def __init__(self, elements = None):
+		if elements is None: elements = []
+		self.elements = MakeExpressionList(elements)
+
+	def add(self, element):
+		self.elements.append(MakeExpression(element))
+
+	def getElements(self):
+		return self.elements
+
+
+class ArrayLength(SimpleExpression):
+	def __init__(self, array_expr):
+		self.array_expr = MakeExpression(array_expr)
+
+	def getArrayExpression(self):
+		return self.array_expr
+
+
+class ArrayElementOperation(Expression):
+	def __init__(self, array_expr, elem_expr):
+		self.array_expr = MakeExpression(array_expr)
+		self.elem_expr = MakeExpression(elem_expr)
+
+	def getArrayExpression(self):
+		return self.array_expr
+
+	def getElementExpression(self):
+		return self.elem_expr
+
+class ArrayIndexOf(ArrayElementOperation, SimpleExpression):
+	def __init__(self, array_expr, elem_expr):
+		ArrayElementOperation.__init__(self, array_expr, elem_expr)
+
+class ArrayContains(ArrayElementOperation, CompoundExpression):
+	def __init__(self, array_expr, elem_expr):
+		ArrayElementOperation.__init__(self, array_expr, elem_expr)
+
+class ArrayPushBack(ArrayElementOperation, SimpleExpression):
+	def __init__(self, array_expr, elem_expr):
+		ArrayElementOperation.__init__(self, array_expr, elem_expr)
+
+
+class NoneExpression(SimpleExpression):
+	pass
+
+
+# helpers
+
+def MakeExpression(expr):
+	if isinstance(expr, Expression):
+		return expr
+	elif isinstance(expr, basestring):
+		return Literal(expr)
+	elif expr is None:
+		return None
+	else:
+		raise Exception("Can't turn argument of type '" + str(type(expr)) + "' into Expression.")
+
+def MakeExpressionList(l):
+	if not isinstance(l, list):
+		raise Exception("Expected argument of type 'list'.")
+	for i in range(len(l)):
+		l[i] = MakeExpression(l[i])
+	return l
+
+def MakeExpressionMap(m):
+	if not isinstance(m, dict):
+		raise Exception("Expected argument of type 'dict'.")
+	for key in m.keys():
+		m[key] = MakeExpression(m[key])
+	return m
+
+def MakeBlockEntry(stmt):
+	if isinstance(stmt, BlockEntry):
+		return stmt
+	elif isinstance(stmt, Expression):
+		return ExpressionStatement(stmt)
+	elif stmt is None:
+		return None
+	else:
+		raise Exception("Can't turn argument of type '" + str(type(stmt)) + "' into BlockEntry.")
+
+def MakeDeclaration(obj):
+	if isinstance(obj, DeclarationBase):
+		return obj
+	else:
+		raise Exception("Can't turn argument of type '" + str(type(stmt)) + "' into DeclarationBase.")
+
+def MakeActualParameters(obj):
+	if isinstance(obj, ActualParameters):
+		return obj
+	elif isinstance (obj, list):
+		return ActualParameters(obj)
+	else:
+		raise Exception("Can't turn argument of type '" + str(type(obj)) + "' into ActualParameters.")
+
+"""def MakeFormalParameter(parameter, default_value):
+	if isinstance(parameter, FormalParameter):
+		return parameter
+	elif default_value:
+		return FormalParameter(parameter, default_value)
+	else:
+		return FormalParameter(parameter)"""
+
+
+class GenericWriterBase(Visitor):
+	__metaclass__ = abc.ABCMeta
+
+	# overrides Visitor.generic_visit
+	def generic_visit(self, node):
+		raise Exception("Writer has no visit method for node of type '" + str(type(node)) + "'.")
+
+	#### HELPERS ####
+
+	def writeAll(self, l):
+		for item in l:
+			item.accept(self)
+
+	def writeTuple(self, obj):
+		self.out.extendWrite("(")
+		self.writeCommaSeparated(obj)
+		self.out.extendWrite(")")
+
+	@abc.abstractmethod
+	def writeComment(self, text):
+		pass
+
+	@abc.abstractmethod
+	def writeMultiLineComment(self, text):
+		pass
+
+	def writeCommaSeparated(self, l):
+		for i in range(len(l)):
+			if i != 0:
+				self.out.extendWrite(", ")
+			l[i].accept(self)
+
+	def writeDescription(self, decl):
+		description = decl.getDescription()
+		if description:
+			self.writeComment(description)
+
+	def writeCompoundExpr(self, expr):
+		if expr.isCompound():
+			self.out.extendWrite("(")
+		expr.accept(self)
+		if expr.isCompound():
+			self.out.extendWrite(")")
+
+	#### VISIT METHODS BASE IMPLEMENTATIONS ####
+
+	def visit_ArrayIndexedExpression(self, i):
+		a = i.getArrayExpression()
+		index = i.getIndexExpression()
+
+		a.accept(self)
+		self.out.extendWrite("[")
+		index.accept(self)
+		self.out.extendWrite("]")
+
+	def visit_ActualParameters(self, p):
+		self.writeTuple(p.getParameterList())
+
+	def visit_AssignmentOperator(self, assign):
+		self.out.extendWrite(" = ")
+
+	def visit_BinaryExpression(self, b):
+		lhs = b.getLhsExpression()
+		rhs = b.getRhsExpression()
+		op = b.getOperator()
+
+		self.writeCompoundExpr(lhs)
+		op.accept(self)
+		self.writeCompoundExpr(rhs)
+
+	def visit_FormalParameters(self, p):
+		self.writeTuple(p.getParameterList())
+
+	def visit_FunctionCall(self, f):
+		func = f.getFunctionExpression()
+		params = f.getActualParameters()
+
+		func.accept(self)
+		params.accept(self)
+
+	def visit_Glue(self, g):
+		self.writeAll(g.getExpressionList())
+
+	def visit_GreaterThanOperator(self, g):
+		self.out.extendWrite(" > ")
+
+	def visit_LessThanOperator(self, l):
+		self.out.extendWrite(" < ")
+
+	def visit_Literal(self, l):
+		self.out.extendWrite(l.getText())
+
+	def visit_MultiLineComment(self, c):
+		self.writeMultiLineComment(c.getText())
+
+	def visit_ProductOperator(self, p):
+		self.out.extendWrite(" * ")
+
+	def visit_Property(self, p):
+		owner = p.getOwnerExpression()
+		prop = p.getProperty()
+
+		owner.accept(self)
+		self.out.extendWrite("." + prop)
+
+	def visit_RawCode(self, c):
+		self.out.writeCodeCorrectIndent(c.getText())
+
+	def visit_SingleLineComment(self, comment):
+		self.writeComment(comment.getText())
+
+	def visit_String(self, string):
+		self.out.extendWrite("\"" + string.getText().replace("\"", "\\\"") + "\"")
+
+	def visit_UnaryExpression(self, u):
+		expr = u.getExpression()
+		op = u.getOperator()
+
+		op.accept(self)
+		self.writeCompoundExpr(expr)
+
+	def visit_VSpace(self, v):
+		self.out.write()
+
+
+class CLikeWriterBase(GenericWriterBase):
+
+	### HELPERS ###
+
+	def writeComment(self, text):
+		self.out.write("// " + text)
+
+	def writeMultiLineComment(self, text):
+		self.out.write("/* " + text + "*/")
+
+	### VISIT METHODS ###
+
+	def visit_AndOperator(self, a):
+		self.out.extendWrite(" && ")
+
+	def visit_Block(self, b):
+		self.out.extendWrite(" {")
+		self.out.indent()
+		self.writeAll(b.getEntries())
+		self.out.dedent()
+		self.out.write("}")
+
+	def visit_BreakStatement(self, b):
+		self.out.write("break;")
+
+	def visit_ElseStatement(self, else_stmt):
+		self.out.extendWrite(" else ")
+		else_stmt.getBody().accept(self)
+
+	def visit_ElseIfStatement(self, else_if):
+		condition = else_if.getCondition()
+		body = else_if.getBody()
+
+		if else_if.isFirst():
+			self.out.write("if (")
+		else:
+			self.out.extendWrite(" else if (")
+		condition.accept(self)
+		self.out.extendWrite(")")
+		body.accept(self)
+
+	def visit_EqualsOperator(self, e):
+		self.out.extendWrite(" == ")
+
+	def visit_ExpressionStatement(self, stmt):
+		self.out.write() # expressions never begin with a newline
+		stmt.getExpression().accept(self)
+		self.out.extendWrite(";")
+
+	def visit_FalseExpression(self, f):
+		self.out.extendWrite("false")
+
+	def visit_IfStatement(self, if_stmt):
+		condition = if_stmt.getCondition()
+		body = if_stmt.getBody()
+
+		self.out.write("if (")
+		condition.accept(self)
+		self.out.extendWrite(")")
+		body.accept(self)
+
+	def visit_NewExpression(self, new):
+		type_expr = new.getTypeExpression()
+		params = new.getActualParameters()
+
+		self.out.extendWrite("new ")
+		type_expr.accept(self)
+		params.accept(self)
+
+	def visit_NotOperator(self, n):
+		self.out.extendWrite("!")
+
+	def visit_OrOperator(self, o):
+		self.out.extendWrite(" || ")
+
+	def visit_ReturnStatement(self, r):
+		self.out.write("return ")
+		r.getExpression().accept(self)
+		self.out.extendWrite(";")
+
+	def visit_SelfExpression(self, s):
+		self.out.extendWrite("this")
+
+	def visit_TrueExpression(self, t):
+		self.out.extendWrite("true")
+
+

+ 285 - 0
hybrid_server/python_sccd_compiler/javascript_writer.py

@@ -0,0 +1,285 @@
+from visitor import Visitor
+from generic_language_constructs import *
+
+class JavascriptWriter(CLikeWriterBase):
+	def __init__(self, outputter):
+		self.out = outputter
+
+	### VISIT METHODS ###
+
+	def visit_ArrayContains(self, a):
+		array = a.getArrayExpression()
+		el = a.getElementExpression()
+
+		self.out.extendWrite("(")
+		array.accept(self)
+		self.out.extendWrite(".indexOf(")
+		el.accept(self)
+		self.out.extendWrite(") !== -1)")
+
+	def visit_ArrayExpression(self, a):
+		elements = a.getElements()
+		if len(elements) == 0:
+			self.out.extendWrite("new Array()")
+		else:
+			self.out.extendWrite("[")
+			self.writeCommaSeparated(elements)
+			self.out.extendWrite("]")
+
+	def visit_ArrayIndexOf(self, a):
+		array = a.getArrayExpression()
+		el = a.getElementExpression()
+
+		array.accept(self)
+		self.out.extendWrite(".indexOf(")
+		el.accept(self)
+		self.out.extendWrite(")")
+
+	def visit_ArrayLength(self, a):
+		a.getArrayExpression().accept(self)
+		self.out.extendWrite(".length")
+
+	def visit_ArrayPushBack(self, a):
+		array = a.getArrayExpression()
+		el = a.getElementExpression()
+
+		array.accept(self)
+		self.out.extendWrite(".push(")
+		el.accept(self)
+		self.out.extendWrite(")")
+
+	def visit_AST(self, ast):
+		self.writeAll(ast.getEntries())
+
+	def visit_Class(self, c):
+		class_name = c.getIdentifier()
+		constructor = c.getConstructor()
+		super_classes = c.getSuperClassIdentifierList()
+		description = c.getDescription()
+
+		self.out.write()
+		if description:
+			self.writeComment(description)
+		constructor.accept(self)
+		if super_classes:
+			self.out.write(class_name + ".prototype = new Object();")
+			self.out.write("(function() {")
+			self.out.indent()
+			for s in super_classes:
+				# workaround for multiple inheritance
+				self.out.write("var proto = new " + s + "();")
+				self.out.write("for (prop in proto) {")
+				self.out.indent()
+				self.out.write(class_name + ".prototype[prop] = proto[prop];")
+				self.out.dedent()
+				self.out.write("}")
+			self.out.dedent()
+			self.out.write("})();")
+		self.writeAll(c.getMembers())
+
+	def visit_Constructor(self, constructor):
+		class_name = constructor.getClass().getIdentifier()
+		parameters = constructor.getFormalParameters()
+		body = constructor.getBody()
+
+		self.out.write("var " + class_name + " = function")
+		parameters.accept(self)
+		body.accept(self)
+		self.out.extendWrite(";")
+
+	def visit_EqualsOperator(self, e):
+		self.out.extendWrite(" === ")
+
+	def visit_ForLoopBody(self, body):
+		for_loop = body.getForLoop()
+		collection_expr = for_loop.getCollectionExpression()
+		iterator_identifier = for_loop.getIteratorIdentifier()
+
+		self.out.extendWrite(" {")
+		self.out.indent()
+		self.out.write("if (!")
+		collection_expr.accept(self)
+		self.out.extendWrite(".hasOwnProperty(" + iterator_identifier + ")) continue;")
+		self.writeAll(body.getEntries())
+		self.out.dedent()
+		self.out.write("}")
+
+	def visit_ForLoopCurrentElement(self, el):
+		collection = el.getCollectionExpression()
+		iterator = el.getIteratorIdentifier()
+
+		collection.accept(self)
+		self.out.extendWrite("["+iterator+"]")
+
+	def visit_ForLoopIterateArray(self, loop):
+		collection = loop.getCollectionExpression()
+		iterator = loop.getIteratorIdentifier()
+		body = loop.getBody()
+
+		self.out.write("for (var " + iterator + " in ")
+		collection.accept(self)
+		self.out.extendWrite(")")
+		body.accept(self)
+
+	def visit_ForLoopIterateMapValues(self, loop):
+		collection = loop.getCollectionExpression()
+		iterator = loop.getIteratorIdentifier()
+		body = loop.getBody()
+
+		self.out.write("for (var " + iterator + " in ")
+		collection.accept(self)
+		self.out.extendWrite(")")
+		body.accept(self)
+
+	def visit_FormalParameter(self, parameter):
+		self.out.extendWrite(parameter.getIdentifier())
+
+	def visit_IncludeStatement(self, i):
+		pass # javascript doesn't have an include mechanism
+
+	def visit_LocalVariableDeclaration(self, decl):
+		identifier = decl.getIdentifier()
+		init_value = decl.getInitValue()
+
+		self.out.extendWrite("var " + identifier)
+		if init_value:
+			self.out.extendWrite(" = ")
+			init_value.accept(self)
+
+	def visit_LogStatement(self, l):
+		self.out.write("console.log(\"" + l.getMessage() + "\");")
+
+	def visit_MapExpression(self, m):
+		elements = m.getElements()
+		if len(elements) == 0:
+			self.out.extendWrite("new Object()")
+		else:
+			self.out.extendWrite("{")
+			keys = elements.keys()
+			for i in range(len(keys)):
+				if i != 0:
+					self.out.extendWrite(", ")			
+				self.out.extendWrite(keys[i] + " : ")
+				self.out.extendWrite(" : ")
+				elements[keys[i]].accept(self)
+			self.out.extendWrite("}")
+
+	def visit_MapIndexedExpression(self, i):
+		m = i.getMapExpression()
+		key = i.getKeyExpression()
+
+		m.accept(self)
+		self.out.extendWrite("[")
+		key.accept(self)
+		self.out.extendWrite("]")
+
+	def visit_MapRemoveElement(self, stmt):
+		map_expr = stmt.getMapExpression()
+		key_expr = stmt.getKeyExpression()
+
+		self.out.write("delete ") # this is a statement, not an expression
+		map_expr.accept(self)
+		self.out.extendWrite("[")
+		key_expr.accept(self)
+		self.out.extendWrite("];")		
+
+	def visit_Method(self, method):
+		class_name = method.getClass().getIdentifier()
+		method_name = method.getIdentifier()
+		description = method.getDescription()
+		body = method.getBody()
+		parameters = method.getFormalParameters()
+
+		self.out.write()
+		if description:
+			self.writeComment(description)
+		self.writeDescription(method)
+		self.out.write(class_name + ".prototype." + method_name + " = function")
+		parameters.accept(self)
+		body.accept(self)
+		self.out.extendWrite(";")
+
+	def visit_MethodBody(self, body):
+		method = body.getMethod()
+		formal_parameters = method.getFormalParameters()
+		formal_parameter_list = formal_parameters.getParameterList()
+
+		self.out.extendWrite(" {")
+		self.out.indent()
+		# check for undefined parameters and replace them with default values
+		for p in formal_parameter_list:
+			p_id = p.getIdentifier()
+			p_default = p.getDefaultValue()
+			if p_default:
+				self.out.write("if (" + p_id + " === undefined) " + p_id + " = ")
+				p_default.accept(self)
+				self.out.extendWrite(";")
+		self.writeAll(body.getEntries())
+		self.out.dedent()
+		self.out.write("}")
+
+	def visit_NoneExpression(self, n):
+		self.out.extendWrite("null")
+
+	def visit_Package(self, package):
+		name = package.getIdentifier()
+		description = package.getDescription()
+
+		self.writeComment("package \"" + name + "\"")
+		if description:
+			self.writeComment(description)
+		self.out.write("var " + name + " = {};")
+		self.out.write("(function() {")
+		for d in package.getDeclarations():
+			d_id = d.getIdentifier()
+			d.accept(self)
+			self.out.write()
+			self.out.write("// add symbol '" + d_id + "' to package '" + name + "'")
+			self.out.write(name + "." + d_id + " = " + d_id + ";")
+		self.out.write("})();")
+
+	def visit_RuntimeModuleIdentifier(self, r):
+		self.out.extendWrite("javascript_runtime")
+
+	def visit_StaticAttribute(self, attr):
+		name = attr.getIdentifier()
+		init_value = attr.getInitValue()
+		class_name = attr.getClass().getIdentifier()
+
+		if init_value:
+			self.out.write(class_name + ".prototype." + name + " = ")
+			init_value.accept(self)
+			self.out.extendWrite(";")
+		else:
+			self.out.write(class_name + ".prototype." + name + " = null;")
+
+	def visit_SuperClassConstructorCall(self, call):
+		super_class = call.getSuperClassIdentifier()
+		params = call.getActualParameters()
+		param_list = [Literal("this")] + params.getParameterList()
+		params = ActualParameters(param_list)
+
+		self.out.extendWrite(super_class)
+		self.out.extendWrite(".call")
+		params.accept(self)
+
+	def visit_SuperClassDestructorCall(self, call):
+		pass # Javascript doesn't have destructors
+
+	def visit_SuperClassMethodCall(self, call):
+		super_class = call.getSuperClassIdentifier()
+		method_name = call.getMethodIdentifier()
+		params = call.getActualParameters()
+		param_list = [Literal("this")] + params.getParameterList()
+		params = ActualParameters(param_list)
+
+		self.out.extendWrite(super_class)
+		self.out.extendWrite(".prototype." + method_name + ".call")
+		params.accept(self)
+
+	def visit_ThrowExceptionStatement(self, stmt):
+		self.out.write("throw new Error(")
+		stmt.getExpression().accept(self)
+		self.out.extendWrite(");")
+
+

+ 170 - 0
hybrid_server/python_sccd_compiler/lexer.py

@@ -0,0 +1,170 @@
+from utils import Enum
+
+TokenType = Enum("SLASH",
+				 "LBRACKET",
+				 "RBRACKET",
+				 "COMMA",
+				 "DOT",
+				 "NUMBER",
+				 "WORD",
+				 "QUOTED",
+				 "WHITESPACE",
+				 "BINARYOPERATOR",
+				 "UNARYOPERATOR",
+				 "UNKNOWN"
+				)
+
+class Token(object):
+	""" A simple Token structure. Token type, value and position.
+	"""
+	def __init__(self, token_type, val, pos):
+		self.type = token_type
+		self.val = val
+		self.pos = pos
+
+	def __str__(self):
+		return '%s(%s) at %s' % (TokenType.name_of(self.type), self.val, self.pos)
+
+
+class LexerError(Exception):
+	def __init__(self, pos):
+		self.pos = pos
+		
+class Lexer(object):
+	single_rules = {
+			'/': TokenType.SLASH,
+			'(': TokenType.LBRACKET,
+			')': TokenType.RBRACKET,
+			',': TokenType.COMMA,
+			'.': TokenType.DOT,
+			'+': TokenType.BINARYOPERATOR,
+			'-': TokenType.BINARYOPERATOR,
+			'<': TokenType.BINARYOPERATOR,
+			'>': TokenType.BINARYOPERATOR,
+			'==': TokenType.BINARYOPERATOR,
+			'<=': TokenType.BINARYOPERATOR,
+			'>=': TokenType.BINARYOPERATOR,
+			'=': TokenType.BINARYOPERATOR,
+			'+=': TokenType.BINARYOPERATOR,
+			'-=': TokenType.BINARYOPERATOR,
+			'&&': TokenType.BINARYOPERATOR,
+			'||': TokenType.BINARYOPERATOR,
+			'!': TokenType.UNARYOPERATOR}
+	
+	def __init__(self, skip_white_space = True, accept_unknown_tokens = False):
+		self.skip_white_space = skip_white_space
+		self.accept_unknown_tokens = accept_unknown_tokens
+
+	def input(self, buf):
+		""" Initialize the lexer with a buffer as input.
+		"""
+		self.buf = buf
+		self.pos = 0
+		self.buflen = len(buf)
+
+	def nextToken(self):
+		""" Return the next token (a Token object) found in the
+			input buffer. None is returned if the end of the
+			buffer was reached.
+			In case of a lexing error (the current chunk of the
+			buffer matches no rule), a LexerError is raised.
+		"""
+		if self.skip_white_space :
+			self.skipWhiteSpace() 
+		if self.pos >= self.buflen:
+			return None
+
+		#c part of next token
+		c = self.buf[self.pos]
+		
+		#check if it is an operator
+		result_type = self.single_rules.get(c,None)
+		if result_type is not None :
+			if self.pos < self.buflen-1:
+				c2 = c+self.buf[self.pos+1]
+				result_type2 = self.single_rules.get(c2, None)
+				if result_type2 is not None:
+					c = c2
+					result_type = result_type2
+					self.pos += 1
+			token = Token(result_type, c, self.pos)
+			self.pos += 1
+			return token
+		else : #not an operator
+			if (self.isAlpha(c)) :
+				return self.processIdentifier()
+			elif (self.isDigit(c)) :
+				return self.processNumber()
+			elif ( c == "'" or c == '"') :
+				return self.processQuote()
+			elif (self.isWhiteSpace(c)) :
+				return self.processWhiteSpace()
+
+		# if we're here, no rule matched
+		if self.accept_unknown_tokens :
+			token = Token(TokenType.UNKNOWN, c, self.pos)
+			self.pos += 1
+			return token
+		raise LexerError("Invalid character at position " + str(self.pos) + ".")
+
+	def tokens(self):
+		""" Returns an iterator to the tokens found in the buffer.
+		"""
+		while True:
+			tok = self.nextToken()
+			if tok is None: break
+			yield tok
+			
+	def skipWhiteSpace(self):
+		while (self.pos < self.buflen) : 
+			if self.isWhiteSpace(self.buf[self.pos]) :
+				self.pos += 1
+			else :
+				break	  
+			
+	def isAlpha(self, c):
+		return c.isalpha() or c == '_';
+	
+	def isAlphaNum(self, c):
+		return c.isalnum() or c == '_';
+	
+	def isDigit(self, c):
+		return c.isdigit()
+	
+	def isWhiteSpace(self, c):
+		return c == ' ' or c == '\t' or c == '\r' or c == '\n'
+	
+	def processNumber(self):
+		nextpos = self.pos + 1
+		while (nextpos < self.buflen) and (self.isDigit(self.buf[nextpos])) :
+			nextpos += 1;
+		token = Token(TokenType.NUMBER, self.buf[self.pos:nextpos], self.pos)
+		self.pos = nextpos
+		return token
+	
+	def processIdentifier(self):
+		nextpos = self.pos + 1
+		while (nextpos < self.buflen) and (self.isAlphaNum(self.buf[nextpos])) :
+			nextpos += 1;
+		token = Token(TokenType.WORD, self.buf[self.pos:nextpos], self.pos)
+		self.pos = nextpos
+		return token
+	
+	def processQuote(self):
+		# self.pos points at the opening quote. Find the ending quote.
+		end_index = self.buf.find(self.buf[self.pos], self.pos + 1)
+	
+		if (end_index == -1) :
+			raise LexerError("Missing matching quote for the quote at position " + str(self.pos) + ".")
+		token = Token(TokenType.QUOTED, self.buf[self.pos:end_index+1], self.pos)
+
+		self.pos = end_index + 1;
+		return token;
+	
+	def processWhiteSpace(self):
+		nextpos = self.pos + 1
+		while (nextpos < self.buflen) and (self.isWhiteSpace(self.buf[nextpos])) :
+			nextpos += 1;
+		token = Token(TokenType.WHITESPACE, self.buf[self.pos:nextpos], self.pos)
+		self.pos = nextpos
+		return token

+ 701 - 0
hybrid_server/python_sccd_compiler/old_generators/csharp_generator.py

@@ -0,0 +1,701 @@
+"""Generates C#"""
+
+import time
+from constructs import FormalParameter
+from code_generation import CodeGenerator, Platforms
+
+class CSharpGenerator(CodeGenerator):
+    
+    def __init__(self):
+        self.supported_platforms = [Platforms.Threads, Platforms.GameLoop]
+                
+    def visit_ClassDiagram(self, class_diagram):
+        self.fOut.write("/*")
+        self.fOut.indent()
+        self.fOut.write("Statecharts + Class Diagram compiler by Glenn De Jonghe")
+        self.fOut.write()
+        self.fOut.write("Date:   " + time.asctime())
+        if class_diagram.name or class_diagram.author or class_diagram.description:
+            self.fOut.write()
+        if class_diagram.author:
+            self.fOut.write("Model author: " + class_diagram.author)
+        if class_diagram.name:
+            self.fOut.write("Model name:   " + class_diagram.name)
+        if class_diagram.description.strip():
+            self.fOut.write("Model description:")
+            self.fOut.write()
+            self.fOut.indent()
+            self.fOut.write(class_diagram.description.strip())
+            self.fOut.dedent()
+        self.fOut.dedent()
+        self.fOut.write('*/')
+        self.fOut.write()
+        
+        #Namespace using declarations by the user
+        self.fOut.write('using System;')
+        self.fOut.write('using System.Collections.Generic;')
+        self.fOut.write('using sccdlib;')
+
+        #User imports
+        if class_diagram.top.strip():
+            self.writeCodeCorrectIndent(class_diagram.top)
+        self.fOut.write()
+        
+        #visit children
+        for c in class_diagram.classes :
+            c.accept(self)
+         
+        #writing out ObjectManager
+        self.fOut.write('public class ObjectManager : ObjectManagerBase')
+        self.fOut.write('{')
+        self.fOut.indent()
+        self.fOut.write('public ObjectManager(ControllerBase controller): base(controller)')
+        self.fOut.write("{")
+        self.fOut.write("}")
+        self.fOut.write()
+        
+        self.fOut.write('protected override InstanceWrapper instantiate(string class_name, object[] construct_params)')
+        self.fOut.write('{')
+        self.fOut.indent()
+        self.fOut.write("RuntimeClassBase instance = null;")
+        self.fOut.write("List<Association> associations = new List<Association>();")
+        for index, c in enumerate(class_diagram.classes) :
+            if index == 0 :
+                self.fOut.write()
+            else :
+                self.fOut.write('}else ')
+            self.fOut.extendWrite('if (class_name == "' + c.name + '" ){')
+            self.fOut.indent()
+            self.fOut.write('object[] new_parameters = new object[construct_params.Length + 1];')
+            self.fOut.write('new_parameters[0] = this.controller;')
+            self.fOut.write('Array.Copy(construct_params, 0, new_parameters, 1, construct_params.Length);')
+            self.fOut.write('instance = (RuntimeClassBase) Activator.CreateInstance(typeof(' + c.name + '), new_parameters);')
+            for a in c.associations :
+                a.accept(self)
+            self.fOut.dedent()
+            if index == len(class_diagram.classes)-1 :
+                self.fOut.write('}')
+            
+        self.fOut.write('if (instance != null) {')
+        self.fOut.indent()
+        self.fOut.write('return new InstanceWrapper(instance, associations);')
+        self.fOut.dedent()
+        self.fOut.write('}')
+        self.fOut.write('return null;')
+        self.fOut.dedent()
+        self.fOut.write('}')
+        self.fOut.dedent()
+        self.fOut.write('}')
+        
+        # write out controller
+        self.fOut.write()
+        if self.platform == Platforms.Threads :
+            controller_sub_class = "ThreadsControllerBase"
+        elif self.platform == Platforms.GameLoop :
+            controller_sub_class = "GameLoopControllerBase"
+        self.fOut.write("public class Controller : " + controller_sub_class)
+        self.fOut.write("{")
+        self.fOut.indent()
+    
+        # write out constructor(s)
+        if class_diagram.default_class.constructors :
+            for constructor in class_diagram.default_class.constructors :
+                self.writeControllerConstructor(class_diagram, constructor.parameters)
+        else :
+            self.writeControllerConstructor(class_diagram)
+        
+        self.fOut.write("public static void Main()")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write("Controller controller = new Controller();")
+        self.fOut.write("controller.start();")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        
+        self.fOut.dedent()
+        self.fOut.write("}")
+        
+    #helper method
+    def writeControllerConstructor(self, class_diagram, parameters = []):
+        self.fOut.write('public Controller(')
+        self.writeFormalParameters(parameters + [FormalParameter("keep_running", "bool", "true")])
+        self.fOut.extendWrite(") : base(keep_running)")
+        self.fOut.write('{')
+        self.fOut.indent()
+        
+        for p in class_diagram.inports:
+            self.fOut.write('this.addInputPort("' + p + '");')
+        for p in class_diagram.outports:
+            self.fOut.write('this.addOutputPort("' + p + '");')
+        self.fOut.write('this.object_manager = new ObjectManager(this);')
+        actual_parameters = [p.getIdent() for p in parameters]
+        self.fOut.write('this.object_manager.createInstance("'+ class_diagram.default_class.name +'", new object[]{' +  ', '.join(actual_parameters)+ '});')
+        self.fOut.dedent()
+        self.fOut.write('}')
+
+    def visit_Class(self, class_node):
+        """
+        Generate code for Class construct
+        """
+        self.fOut.write()
+        self.fOut.write("public class " + class_node.name )
+        # Take care of inheritance
+        if len(class_node.super_classes) > 1 :
+            raise Exception("C# doesn't allow multiple inheritance.");
+        elif len(class_node.super_classes) == 1 :
+            self.fOut.extendWrite(" : " + class_node.super_classes[0])
+        else :
+            self.fOut.extendWrite(" : " + "RuntimeClassBase")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write()
+        
+        if class_node.statechart is not None:
+            # assign each node a unique ID
+            self.fOut.write("/// <summary>")
+            self.fOut.write("/// Enum uniquely representing all statechart nodes.")
+            self.fOut.write("/// </summary>")
+            self.fOut.write("public enum Node {")
+            self.fOut.indent()
+            for node in class_node.statechart.composites + class_node.statechart.basics:
+                self.fOut.write(node.full_name + ",");
+            self.fOut.dedent();
+            self.fOut.write("};")
+            self.fOut.write()
+            self.fOut.write("Dictionary<Node,List<Node>> current_state = new Dictionary<Node,List<Node>>();");
+            if len(class_node.statechart.histories) > 0 :
+                self.fOut.write("Dictionary<Node,List<Node>> history_state = new Dictionary<Node,List<Node>>();");
+            self.fOut.write();
+            
+        #User defined attributes
+        if class_node.attributes:
+            self.fOut.write("//User defined attributes")
+            for attribute in class_node.attributes:
+                self.fOut.write(attribute.type + " " + attribute.name)
+                if attribute.init_value is not None :
+                    self.fOut.write(" = " + attribute.init_value);
+                self.fOut.extendWrite(";")     
+            self.fOut.write()
+
+        if class_node.statechart is not None:  
+            self.fOut.write("/// <summary>")
+            self.fOut.write("/// Constructor part that is common for all constructors.")
+            self.fOut.write("/// </summary>")
+            self.fOut.write("private void commonConstructor(ControllerBase controller = null)")
+            self.fOut.write("{")
+            self.fOut.indent() 
+            self.fOut.write("this.controller = controller;")
+            self.fOut.write("this.object_manager = controller.getObjectManager();")
+            if class_node.statechart.nr_of_after_transitions != 0:
+                self.fOut.write("this.timers = new Dictionary<int,double>();")
+
+            self.fOut.write()
+            self.fOut.write("//Initialize statechart :")
+            self.fOut.write()
+
+            if class_node.statechart.histories:
+                for node in class_node.statechart.combined_history_parents:
+                    self.fOut.write("this.history_state[Node." + node.full_name + "] = new List<Node>();")
+                self.fOut.write()
+
+            for node in class_node.statechart.composites :
+                self.fOut.write("this.current_state[Node." + node.full_name + "] = new List<Node>();")
+                
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+        self.fOut.write("public override void start()")
+        self.fOut.write("{")
+        
+        self.fOut.indent()
+        self.fOut.write("base.start();")
+        for default_node in class_node.statechart.root.defaults:
+            if default_node.is_composite:
+                self.fOut.write("this.enterDefault_" + default_node.full_name + "();")
+            elif default_node.is_basic:
+                self.fOut.write("this.enter_" + default_node.full_name + "();")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+        #visit children
+        for i in class_node.constructors :
+            i.accept(self)
+        for i in class_node.destructors :
+            i.accept(self)
+        for i in class_node.methods :
+            i.accept(self)
+        if class_node.statechart is not None:
+            class_node.statechart.accept(self)
+          
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+
+    def writeFormalParameters(self, parameters = []):
+        """Helper method that writes a correct comma separated list of formal parameters"""    
+        first = True       
+        for param in parameters :
+            if first :
+                first = False
+            else :
+                self.fOut.extendWrite(', ')
+            param.accept(self)
+        
+    def visit_FormalParameter(self, formal_parameter):
+        self.fOut.extendWrite(formal_parameter.getType() + " " + formal_parameter.getIdent())
+        if formal_parameter.hasDefault() :
+            self.fOut.extendWrite(" = " + formal_parameter.getDefault())
+                    
+    def visit_Constructor(self, constructor):
+
+        self.fOut.write(constructor.access + " " + constructor.parent_class.name + "(")
+        self.writeFormalParameters([FormalParameter("controller", "ControllerBase", None)] + constructor.getParams())
+        self.fOut.extendWrite(")")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write("this.commonConstructor(controller);")
+        if constructor.body :
+            self.fOut.write()
+            self.fOut.write("//constructor body (user-defined)")
+            self.writeCodeCorrectIndent(constructor.body)
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+    def visit_Destructor(self, destructor):
+        self.fOut.write("~" + destructor.parent_class.name + "()")
+        self.fOut.write("{")
+        if destructor.body :
+            self.fOut.indent()
+            self.writeCodeCorrectIndent(destructor.body)
+            self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+    def visit_Method(self, method):
+        self.fOut.write(method.access + " " + method.return_type + " " + method.name + "(")
+        self.writeFormalParameters(method.getParams())
+        self.fOut.extendWrite(")")
+        self.fOut.write("{")
+        self.fOut.indent()
+        if method.body :
+            self.fOut.indent()
+            self.writeCodeCorrectIndent(method.body)
+            self.fOut.dedent()
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+    def visit_Association(self, association):
+        self.fOut.write('associations.Add(new Association("' + association.name + '", "' + association.to_class + '", ' + str(association.min) + ', ' + str(association.max) + '));')
+        
+    #helper method
+    def writeTransitionsRecursively(self, current_node):
+        self.fOut.write("private bool transition_" + current_node.full_name + "(Event e)")
+        self.fOut.write("{")
+        self.fOut.indent()
+        
+        valid_children = []
+        for child in current_node.children :
+            if child.is_composite or child.is_basic :
+                valid_children.append(child)  
+         
+        self.fOut.write("bool catched = false;")
+        do_dedent = False
+        if current_node.solves_conflict_outer :
+            self.writeFromTransitions(current_node)
+            if current_node.is_parallel_state or current_node.is_composite :
+                self.fOut.write("if (!catched){")
+                self.fOut.indent()
+                do_dedent = True
+            
+        if current_node.is_parallel_state:
+            for child in valid_children :     
+                self.fOut.write("catched = this.transition_" + child.full_name + "(e) || catched;")
+        elif current_node.is_composite:
+            self.fOut.write()
+            for i, child in enumerate(valid_children) :
+                if i > 0 :
+                    self.fOut.extendWrite(" else ")
+                self.fOut.extendWrite("if (this.current_state[Node." + current_node.full_name + "][0] == Node." + child.full_name + "){")
+                self.fOut.indent()
+                self.fOut.write("catched = this.transition_" + child.full_name + "(e);")
+                self.fOut.dedent()
+                self.fOut.write("}")
+                
+        if current_node.solves_conflict_outer :
+            if do_dedent :
+                self.fOut.dedent()
+                self.fOut.write("}")
+        elif len(current_node.transitions) > 0 :
+                self.fOut.write("if (!catched) {")
+                self.fOut.indent()
+                self.writeFromTransitions(current_node)
+                self.fOut.dedent()
+                self.fOut.write("}")
+            
+        self.fOut.write("return catched;")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write();
+        
+        for child in valid_children :
+            self.writeTransitionsRecursively(child)
+                
+    #helper method
+    def writeFromTransitions(self, current_node): 
+        # get all transition out of this state
+        out_transitions = current_node.transitions
+        if len(out_transitions) == 0 :
+            return
+        
+        self.fOut.write('List<int> enableds = new List<int>();')
+        for index, transition in enumerate(out_transitions):
+            self.writeTransitionCondition(transition, index)
+            
+        self.fOut.write("if (enableds.Count > 1){")
+        self.fOut.indent()
+        self.fOut.write('Console.WriteLine("Runtime warning : indeterminism detected in a transition from node ' +  current_node.full_name+ '. Only the first in document order enabled transition is executed.");')
+        self.fOut.dedent()
+        self.fOut.write('}')
+        self.fOut.write("if (enableds.Count > 0){")
+        self.fOut.indent()
+        self.fOut.write('int enabled = enableds[0];')
+        self.fOut.write()      
+              
+        for index, transition in enumerate(out_transitions):
+            self.writeTransitionAction(transition, index)
+        
+        self.fOut.write('catched = true;')   
+        self.fOut.dedent()
+        self.fOut.write('}')         
+        self.fOut.write()
+        
+    def visit_FormalEventParameter(self, formal_event_parameter):
+        self.fOut.extendWrite(formal_event_parameter.getType() + " " + formal_event_parameter.name)
+        
+    def writeFormalEventParameters(self, transition):
+        parameters = transition.getTrigger().getParameters()
+        if(len(parameters) > 0) :
+            self.fOut.write('object[] parameters = e.getParameters();')
+            for index, parameter in enumerate(parameters):
+                self.fOut.write()
+                parameter.accept(self)
+                self.fOut.extendWrite(' = (' + parameter.getType() + ')parameters[' + str(index) + '];')
+        
+    def writeTransitionAction(self, transition, index):
+        if index > 1 :
+            self.fOut.extendWrite(" else ")
+        else :
+            self.fOut.write()
+        self.fOut.extendWrite("if (enabled == " + str(index) + "){")
+        self.fOut.indent()
+
+        # handle parameters to actually use them             
+        self.writeFormalEventParameters(transition)
+        
+        exits = transition.getExitNodes()
+        
+        # write out exit actions
+        if not exits[-1].is_basic:
+            self.fOut.write("this.exit_" + exits[-1].full_name + "();")
+        else:
+            for node in exits:
+                if node.is_basic:
+                    self.fOut.write("this.exit_" + node.full_name + "();")
+                    
+        # write out trigger actions
+        transition.getAction().accept(self)
+        
+        for (entering_node, is_ending_node) in transition.getEnterNodes() : 
+            if is_ending_node :
+                if entering_node.is_composite:
+                    self.fOut.write("this.enterDefault_" + entering_node.full_name + "();")
+                elif entering_node.is_history:
+                    if (entering_node.is_history_deep) :
+                        self.fOut.write("this.enterHistoryDeep_" + entering_node.parent.full_name + "();")
+                    else :
+                        self.fOut.write("this.enterHistoryShallow_" + entering_node.parent.full_name + "();")
+                else:
+                    self.fOut.write("this.enter_" + entering_node.full_name + "();")
+            else :
+                if entering_node.is_composite:
+                    self.fOut.write("this.enter_" + entering_node.full_name + "();")
+
+        self.fOut.dedent()
+        self.fOut.write('}')
+                        
+    def writeTransitionCondition(self, transition, index):
+        trigger = transition.getTrigger()
+        if not trigger.isUC():  
+            self.fOut.write('if (e.getName() == "' + trigger.getEvent() + '" && e.getPort() == "' + trigger.getPort() + '"){')
+            self.fOut.indent()   
+        # evaluate guard
+        if transition.hasGuard() :   
+            # handle parameters for guard evaluation       
+            self.writeFormalEventParameters(transition)  
+
+            self.fOut.write('if (')
+            transition.getGuard().accept(self)
+            self.fOut.extendWrite('){')
+            self.fOut.indent()    
+            
+        self.fOut.write("enableds.Add(" + str(index) + ");")
+
+        if transition.hasGuard() :
+            self.fOut.dedent()
+            self.fOut.write('}')
+        if not trigger.isUC() :
+            self.fOut.dedent()
+            self.fOut.write('}')
+        self.fOut.write()
+    
+    def visit_EnterAction(self, enter_method):
+        parent_node = enter_method.parent_node
+        self.fOut.write("private void enter_" + parent_node.full_name + "()")
+        self.fOut.write("{")
+        self.fOut.indent()
+        
+        # take care of any AFTER events
+        for transition in parent_node.transitions :
+            trigger = transition.getTrigger()
+            if trigger.isAfter() :
+                self.fOut.write("this.timers[" + str(trigger.getAfterIndex()) + "] = ")
+                trigger.after.accept(self)
+                self.fOut.extendWrite(";")
+        if enter_method.action:
+            enter_method.action.accept(self)
+        self.fOut.write("this.current_state[Node." + parent_node.parent.full_name + "].Add(Node." + parent_node.full_name + ");")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+    #helper method
+    def writeEnterDefault(self, entered_node):
+        self.fOut.write("private void enterDefault_" + entered_node.full_name + "()")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write("this.enter_" + entered_node.full_name + "();")
+        if entered_node.is_composite:
+            l = entered_node.defaults
+            for i in l:
+                if i.is_composite:
+                    self.fOut.write("this.enterDefault_" + i.full_name + "();")
+                elif i.is_basic:
+                    self.fOut.write("this.enter_" + i.full_name + "();")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+         
+    def visit_ExitAction(self, exit_method):
+        exited_node = exit_method.parent_node
+        self.fOut.write("private void exit_" + exited_node.full_name + "()")
+        self.fOut.write("{")
+        self.fOut.indent()
+        #If the exited node is composite take care of potential history and the leaving of descendants
+        if exited_node.is_composite :
+            #handle history
+            if exited_node.save_state_on_exit:
+                self.fOut.write("this.history_state[Node." + exited_node.full_name + "].AddRange(this.current_state[Node." + exited_node.full_name + "]);")
+            
+            #Take care of leaving children
+            children = exited_node.children
+            if exited_node.is_parallel_state:
+                for child in children:
+                    if not child.is_history :
+                        self.fOut.write("this.exit_" + child.full_name + "();")
+            else:
+                for child in children:
+                    if not child.is_history :
+                        self.fOut.write("if (this.current_state[Node." + exited_node.full_name + "].Contains(Node." + child.full_name +  ")){")
+                        self.fOut.indent()
+                        self.fOut.write("this.exit_" + child.full_name + "();")
+                        self.fOut.dedent()  
+                        self.fOut.write("}")
+        
+        
+        # take care of any AFTER events
+        for transition in exited_node.transitions :
+            trigger = transition.getTrigger()
+            if trigger.isAfter() :
+                self.fOut.write("this.timers.Remove(" + str(trigger.getAfterIndex()) + ");")
+                
+        #Execute user-defined exit action if present
+        if exit_method.action:
+            exit_method.action.accept(self)
+            
+        #Adjust state
+        self.fOut.write("this.current_state[Node." + exited_node.parent.full_name + "].Remove(Node." + exited_node.full_name + ");")
+
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+            
+    #helper method
+    def writeEnterHistory(self, entered_node, is_deep):
+        self.fOut.write("private void enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name + "()")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write("if (this.history_state[Node." + entered_node.full_name + "].Count == 0){")
+        self.fOut.indent()
+        defaults = entered_node.defaults
+
+        for node in defaults:
+            if node.is_basic :
+                self.fOut.write("this.enter_" + node.full_name + "();")
+            elif node.is_composite :
+                self.fOut.write("this.enterDefault_" + node.full_name + "();")
+
+        self.fOut.dedent()
+        self.fOut.write("} else {")
+        self.fOut.indent()
+        children = entered_node.children
+        if entered_node.is_parallel_state:
+            for child in children:
+                if not child.is_history :
+                    self.fOut.write("this.enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + child.full_name + "();")
+        else:
+            for child in children:
+                if not child.is_history :
+                    self.fOut.write("if (this.history_state[Node." + entered_node.full_name + "].Contains(Node." + child.full_name + ")){")
+                    self.fOut.indent()
+                    if child.is_composite:
+                        if is_deep :
+                            self.fOut.write("this.enter_" + child.full_name + "();")
+                            self.fOut.write("this.enterHistoryDeep_" + child.full_name + "();")
+                        else :
+                            self.fOut.write("this.enterDefault_" + child.full_name + "();")
+                    else:
+                        self.fOut.write("this.enter_" + child.full_name + "();")
+                    self.fOut.dedent()
+                    self.fOut.write("}")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+
+    def visit_StateChart(self, statechart):
+        self.fOut.write("//Statechart enter/exit action method(s) :")
+        self.fOut.write()
+        
+        #visit enter and exit actions of children
+        for i in statechart.composites + statechart.basics:
+            if i is not statechart.root :
+                i.enter_action.accept(self)
+                i.exit_action.accept(self)
+
+        # write out statecharts methods for enter/exit state
+        if len(statechart.composites) > 1 :
+            self.fOut.write("//Statechart enter/exit default method(s) :")
+            self.fOut.write()
+            for i in statechart.composites :
+                if i is not statechart.root :
+                    self.writeEnterDefault(i)
+
+        # write out statecharts methods for enter/exit history
+        if statechart.histories:
+            self.fOut.write("//Statechart enter/exit history method(s) :")
+            self.fOut.write()
+            for i in statechart.shallow_history_parents:
+                self.writeEnterHistory(i, False)
+            for i in statechart.deep_history_parents:
+                self.writeEnterHistory(i, True)   
+                
+        self.fOut.write("//Statechart transitions :")
+        self.fOut.write()
+        self.writeTransitionsRecursively(statechart.root)            
+                
+        # write out transition function
+        self.fOut.write("protected override void transition (Event e = null)")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write("if (e == null) {");
+        self.fOut.indent()
+        self.fOut.write("e = new Event();")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write("this.state_changed = this.transition_" + statechart.root.full_name + "(e);")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+
+        # write out inState function
+        self.fOut.write("public bool inState(List<Node> nodes)")
+        self.fOut.write("{")
+        self.fOut.indent()
+        self.fOut.write("foreach(List<Node> actives in current_state.Values){")
+        self.fOut.indent()
+        self.fOut.write("foreach(Node node in actives)")
+        self.fOut.indent()
+        self.fOut.write("nodes.Remove (node);")
+        self.fOut.dedent()
+        self.fOut.write("if (nodes.Count == 0){")
+        self.fOut.indent()
+        self.fOut.write("return true;")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write("return false;")
+        self.fOut.dedent()
+        self.fOut.write("}")
+        self.fOut.write()
+        
+    def visit_ExpressionPartString(self, bare_string):
+        self.fOut.extendWrite(bare_string.string)
+        
+    def visit_SelfReference(self, self_reference):
+        self.fOut.extendWrite("this")
+        
+    def visit_StateReference(self, state_ref):
+        self.fOut.extendWrite("new List<Node>() {")
+        self.fOut.extendWrite(", ".join(["Node." + node.full_name for node in state_ref.getNodes()]))
+        self.fOut.extendWrite("}")
+        
+    def visit_InStateCall(self, in_state_call):
+        self.fOut.extendWrite("this.inState(")
+        in_state_call.target.accept(self)
+        self.fOut.extendWrite(")")
+        
+    def visit_RaiseEvent(self, raise_event):
+        if raise_event.isNarrow() or raise_event.isBroad():
+            self.fOut.write('Event send_event = new Event("' + raise_event.getEventName() + '", "", new object[] {')
+        elif raise_event.isLocal():
+            self.fOut.write('this.addEvent( new Event("' + raise_event.getEventName() +'", "", new object[] {')
+        elif raise_event.isOutput():
+            self.fOut.write('this.controller.outputEvent(new Event("' + raise_event.getEventName() + '", "' + raise_event.getPort() + '", new object[] {')
+        elif raise_event.isCD():
+            self.fOut.write('this.object_manager.addEvent(new Event("' + raise_event.getEventName() + '", "", new object[] { this, ')
+        first_param = True
+        for param in raise_event.getParameters() :
+            if first_param :
+                first_param = False
+            else :
+                self.fOut.extendWrite(',')
+            param.accept(self)
+        if raise_event.isNarrow():
+            self.fOut.extendWrite('});')
+            self.fOut.write('this.object_manager.addEvent(new Event("narrow_cast", "", new object[] {this, "' + raise_event.getTarget() + '" ,send_event}));')
+        elif raise_event.isBroad():
+            self.fOut.extendWrite('});')
+            self.fOut.write('this.object_manager.addEvent(new Event("broad_cast", "", new object[] {send_event}));')
+        else :
+            self.fOut.extendWrite('}));')
+            
+    def visit_Script(self, script):
+        self.writeCodeCorrectIndent(script.code)
+        
+    def visit_Log(self, log):
+        self.fOut.write('Console.WriteLine("' + log.message + '");')
+        
+    def visit_Assign(self, assign):
+        self.fOut.write()
+        assign.lvalue.accept(self)
+        self.fOut.extendWrite(" = ")
+        assign.expression.accept(self)
+        self.fOut.extendWrite(";")
+        

+ 741 - 0
hybrid_server/python_sccd_compiler/old_generators/javascript_generator.py

@@ -0,0 +1,741 @@
+import time
+from constructs import FormalParameter
+from code_generation import CodeGenerator, Platforms
+
+class JavascriptGenerator(CodeGenerator):
+	
+	def __init__(self):
+		self.supported_platforms = [Platforms.Threads, Platforms.GameLoop]
+				
+	def visit_ClassDiagram(self, class_diagram):
+		# header
+		self.fOut.write("/**");
+		self.fOut.write(" * Statechart compiler by Glenn De Jonghe")
+		self.fOut.write(" * Javascript generator by Joeri Exelmans")
+		self.fOut.write(" * ")
+		self.fOut.write(" * Date:   " + time.asctime())
+		if class_diagram.name or class_diagram.author or class_diagram.description:
+			self.fOut.write(" * ")
+		if class_diagram.author:
+			self.fOut.write(" * Model author: " + class_diagram.author)
+		if class_diagram.name:
+			self.fOut.write(" * Model name:   " + class_diagram.name)
+		if class_diagram.description.strip():
+			self.fOut.write(" * Model description:")
+			self.fOut.indent()
+			self.fOut.write(class_diagram.description.strip())
+			self.fOut.dedent()
+		self.fOut.write(" */")
+		
+		self.fOut.write()
+
+		self.fOut.write("// put everything in an object (serves as \"namespace\")")
+		self.fOut.write(class_diagram.name + " = {};")
+		self.fOut.write()
+		self.fOut.write("// closure scope")
+		self.fOut.write("(function() {")
+		self.fOut.write()
+		
+		#visit children
+		for c in class_diagram.classes :
+			c.accept(self)
+			self.fOut.write("// put class in global diagram object")
+			self.fOut.write(class_diagram.name + '.' + c.name + ' = ' + c.name + ';')
+			self.fOut.write()
+		 
+		#writing out ObjectManager
+		self.fOut.write('var ObjectManager = function(controller) {')
+		self.fOut.indent()
+		self.fOut.write("ObjectManagerBase.call(this, controller);")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+
+		self.fOut.write("ObjectManager.prototype = new ObjectManagerBase();")
+		self.fOut.write()
+		
+		self.fOut.write('ObjectManager.prototype.instantiate = function(class_name, construct_params) {')
+		self.fOut.indent()
+		for index, c in enumerate(class_diagram.classes) :
+			if index == 0 : 
+				self.fOut.write()
+			else :
+				self.fOut.extendWrite(' else ')
+			self.fOut.extendWrite('if (class_name === "' + c.name + '") {')
+			self.fOut.indent()
+			if c.statechart :
+				self.fOut.write('var instance = new ' + c.name + '(this.controller')
+				param_count = 0
+				for p in c.constructors[0].parameters:
+					self.fOut.extendWrite(', construct_params[' + str(param_count) + ']')
+					param_count += 1
+				self.fOut.extendWrite(');')
+			else :
+				self.fOut.write('var instance = new ' + c.name + '(')
+				param_count = 0
+				for p in c.constructors[0].parameters:
+					if (param_count != 0):
+						self.fOut.extendWrite(', ')
+					self.fOut.extendWrite('construct_params[' + str(param_count) + ']')
+					param_count += 1
+				self.fOut.extendWrite(');');
+			self.fOut.write('instance.associations = new Object();')
+			for a in c.associations :
+				a.accept(self)
+			self.fOut.dedent()
+			self.fOut.write('}')
+		self.fOut.write('return instance;')
+		self.fOut.dedent()
+		self.fOut.write("};")
+
+		self.fOut.write()
+		self.fOut.write("// put in global diagram object")
+		self.fOut.write(class_diagram.name + '.ObjectManager = ObjectManager;')
+
+		self.fOut.write()
+		if self.platform == Platforms.Threads :
+			controller_sub_class = "JsEventLoopControllerBase"
+		elif self.platform == Platforms.GameLoop :
+			controller_sub_class = "GameLoopControllerBase"
+
+		# write out __init__ method
+		if class_diagram.default_class.constructors :
+			self.writeControllerConstructor(class_diagram, controller_sub_class, class_diagram.default_class.constructors[0].parameters)
+		else :
+			self.writeControllerConstructor(class_diagram, controller_sub_class)
+
+		self.fOut.write("Controller.prototype = new " + controller_sub_class + "();")
+		self.fOut.write()
+		self.fOut.write("// put in global diagram object")
+		self.fOut.write(class_diagram.name + '.Controller = Controller;')
+		self.fOut.write()
+		self.fOut.write("})();")
+		self.fOut.write()
+
+	#helper method
+	def writeControllerConstructor(self, class_diagram, controller_sub_class, parameters = []):
+		self.writeConstructorSignature("Controller", parameters + [FormalParameter("keep_running", "", "true"), FormalParameter("finished_callback", "", None)])
+		self.fOut.indent()
+		self.fOut.write(controller_sub_class + ".call(this, new ObjectManager(this), keep_running, finished_callback);")
+		for i in class_diagram.inports:
+			self.fOut.write('this.addInputPort("' + i + '");')
+		for i in class_diagram.outports:
+			self.fOut.write('this.addOutputPort("' + i + '");')
+		actual_parameters = [p.getIdent() for p in parameters]
+		self.fOut.write('this.object_manager.createInstance("'+ class_diagram.default_class.name +'", [' +  ', '.join(actual_parameters)+ ']);')
+		self.fOut.dedent()
+		self.fOut.write('};')
+		self.fOut.write()
+
+	def visit_Class(self, class_node):
+		"""
+		Generate code for Class construct
+		"""
+
+		if class_node.super_classes:
+			super_classes = []
+			for super_class in class_node.super_classes:
+				super_classes.append(super_class)
+		else:
+			super_classes = ["RuntimeClassBase"]
+
+		#visit children
+		for i in class_node.constructors :
+			i.accept(self)
+
+		self.fOut.write()
+		self.fOut.write(class_node.name + ".prototype = new " + super_classes[0] + "();")
+		self.fOut.write()
+
+		if class_node.statechart is not None:
+			# assign each node a unique ID
+			self.fOut.write("// Unique IDs for all statechart nodes")
+			for (i,node) in enumerate(class_node.statechart.composites + class_node.statechart.basics):
+				self.fOut.write(class_node.name + ".prototype." + node.full_name + " = " + str(i) + ";")
+			self.fOut.write()
+
+		#visit children
+		for i in class_node.destructors :
+			i.accept(self)
+		for i in class_node.methods :
+			i.accept(self)
+		if class_node.statechart is not None:
+			class_node.statechart.accept(self)
+
+		self.writeMethodSignature(class_node.name, "user_defined_constructor", class_node.constructors[0].getParams())
+
+		self.fOut.indent()
+
+		for super_class in class_node.super_classes:
+			self.fOut.write(super_class + ".prototype.user_defined_constructor.call(this")
+			for p in class_node.constructors[0].super_class_parameters[super_class]:
+				self.fOut.extendWrite(", " + p)
+			self.fOut.extendWrite(");")
+
+
+		self.writeCodeCorrectIndent(class_node.constructors[0].body)
+		
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+		
+		self.writeMethodSignature(class_node.name, "start")
+		self.fOut.indent()
+		self.fOut.write(super_classes[0] + ".prototype.start.call(this);")
+		for default_node in class_node.statechart.root.defaults:
+			if default_node.is_composite:
+				self.fOut.write("this.enterDefault_" + default_node.full_name + "();")
+			elif default_node.is_basic:
+				self.fOut.write("this.enter_" + default_node.full_name + "();")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+
+	#helper method
+	def writeConstructorSignature(self, prototype_name, parameters = []):
+		self.fOut.write("var " + prototype_name + " = function(")		   
+		for param in parameters :
+			if parameters.index(param) != 0:
+				self.fOut.extendWrite(', ')
+			param.accept(self)
+		self.fOut.extendWrite(") {")
+		self.fOut.indent()
+		for param in parameters :
+			if param.hasDefault() :
+				self.fOut.write("if (" + param.getIdent() + " === undefined) " +
+					param.getIdent() + " = " + param.getDefault() + ";")
+		self.fOut.dedent()
+
+	#helper method
+	def writeMethodSignature(self, prototype_name, method_name, parameters = []):
+		self.fOut.write(prototype_name + ".prototype." + method_name + " = function(")
+		for param in parameters :
+			if parameters.index(param) != 0 :
+				self.fOut.extendWrite(', ')
+			param.accept(self)
+		self.fOut.extendWrite(") {")
+		self.fOut.indent()
+		for param in parameters :
+			if param.hasDefault() :
+				self.fOut.write("if (!" + param.getIdent() + ") " +
+					param.getIdent() + " = " + param.getDefault() + ";")
+		self.fOut.dedent()
+		
+	#helper method
+	def writeMethod(self, prototype_name, name, parameters, return_type, body):
+		self.writeMethodSignature(prototype_name, name, parameters)
+		self.fOut.indent()
+		if body.strip():
+			self.writeCodeCorrectIndent(body)
+		self.fOut.write()
+		self.fOut.dedent()
+		self.fOut.write("};");
+		
+	def visit_FormalParameter(self, formal_parameter):
+		self.fOut.extendWrite(formal_parameter.getIdent())
+		
+	def visit_Constructor(self, constructor):
+		self.fOut.write("// Constructor")
+		parameters =  [FormalParameter("controller", "", None)] + constructor.getParams()
+		self.writeConstructorSignature(constructor.parent_class.name, parameters)
+		self.fOut.indent()
+
+		if constructor.parent_class.super_classes:
+			self.fOut.write(constructor.parent_class.super_classes[0] + ".call(this);")
+		else:
+			self.fOut.write("RuntimeClassBase.call(this);")
+
+		self.fOut.write()
+		self.fOut.write("if (controller) {")
+		self.fOut.indent()
+
+		#visit input, output ports
+		self.fOut.write("// User defined input ports")
+		self.fOut.write("this.inports = new Object();")
+		for p in constructor.parent_class.inports:
+			self.fOut.write("this.inports[\""+p+"\"] = controller.addInputPort(\""+p+"\", this);")
+
+		#for p in class_node.outports:
+
+		# write attributes
+		if constructor.parent_class.attributes:
+			self.fOut.write()
+			self.fOut.write("// User defined attributes")
+			for attribute in constructor.parent_class.attributes:
+				if attribute.init_value is None :
+					self.fOut.write("this." +  attribute.name + " = null;")
+				else :
+					self.fOut.write("this." +  attribute.name + " = " + attribute.init_value + ";")
+			self.fOut.write()
+
+		# if there is a statechart
+		if constructor.parent_class.statechart is not None:			
+			self.fOut.write("this.controller = controller;")
+			self.fOut.write("this.object_manager = controller.object_manager;")
+			self.fOut.write("this.current_state = new Object();")
+			self.fOut.write("this.history_state = new Object();")
+			if constructor.parent_class.statechart.nr_of_after_transitions:
+				self.fOut.write("this.timers = new Object();")
+			self.fOut.write()
+			self.fOut.write("// Initialize statechart")
+			
+			if constructor.parent_class.statechart.histories:
+				for node in constructor.parent_class.statechart.combined_history_parents:
+					self.fOut.write("this.history_state[" + constructor.parent_class.name + "." + node.full_name + "] = new Array();")
+				self.fOut.write()
+
+			for c in constructor.parent_class.statechart.composites :
+				self.fOut.write("this.current_state[this." + c.full_name + "] = new Array();")
+
+		self.fOut.write()
+		self.fOut.write("// Call user defined constructor")
+		self.fOut.write(constructor.parent_class.name + ".prototype.user_defined_constructor.call(this")
+		for p in constructor.getParams():
+			self.fOut.extendWrite(", ")
+			p.accept(self)
+		self.fOut.extendWrite(");")
+
+
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+
+	def visit_Destructor(self, destructor):
+		self.fOut.write("// User defined destructor")
+
+		self.writeMethodSignature(destructor.parent_class.name, "user_defined_destructor", [])
+		self.fOut.indent()
+		if destructor.body.strip():
+			self.writeCodeCorrectIndent(destructor.body)
+
+		if destructor.parent_class.super_classes:
+			self.fOut.write()
+			self.fOut.write("// Call super class destructors")
+			for super_class in destructor.parent_class.super_classes:
+				self.fOut.write(super_class + ".prototype.user_defined_destructor.call(this);")
+
+		self.fOut.dedent()
+		self.fOut.write("};");
+		self.fOut.write()
+		
+	def visit_Method(self, method):
+		self.fOut.write("// User defined method")
+		self.writeMethod(method.parent_class.name, method.name, method.parameters, method.return_type, method.body)
+		
+	def visit_Association(self, association):
+		self.fOut.write('instance.associations["' + association.name + '"] = new Association("' + association.to_class + '", ' + str(association.min) + ', ' + str(association.max) + ');')
+		
+	#helper method
+	def writeTransitionsRecursively(self, current_node):
+
+		self.writeMethodSignature(current_node.statechart.class_obj.name, "transition_" + current_node.full_name, [FormalParameter("event", "event")])
+		self.fOut.indent()
+		
+		valid_children = []
+		for child in current_node.children :
+			if child.is_composite or child.is_basic :
+				valid_children.append(child)  
+		 
+		self.fOut.write("var catched = false;")
+		do_dedent = False
+		if current_node.solves_conflict_outer :
+			self.writeFromTransitions(current_node)
+			if current_node.is_parallel_state or current_node.is_composite :
+				self.fOut.write("if (!catched) {")
+				self.fOut.indent()
+				do_dedent = True
+			
+		if current_node.is_parallel_state:
+			for child in valid_children :	 
+				self.fOut.write("catched = this.transition_" + child.full_name + "(event) || catched")
+		elif current_node.is_composite:
+			for i, child in enumerate(valid_children) :
+				if i > 0 :
+					self.fOut.write("else ")
+				else :
+					self.fOut.write()
+				self.fOut.extendWrite("if (this.current_state[this." + current_node.full_name + "][0] === this." + child.full_name + ") {")
+				self.fOut.indent()
+				self.fOut.write("catched = this.transition_" + child.full_name + "(event);")
+				self.fOut.dedent()
+				self.fOut.write("}")
+				
+		if current_node.solves_conflict_outer :
+			if do_dedent :
+				self.fOut.dedent()
+				self.fOut.write("}")
+		elif len(current_node.transitions) > 0 :
+				self.fOut.write("if (!catched) {")
+				self.fOut.indent()
+				self.writeFromTransitions(current_node)
+				self.fOut.dedent()
+				self.fOut.write("}");
+			
+		self.fOut.write("return catched;")
+		self.fOut.dedent()
+		self.fOut.write("};");
+		self.fOut.write();
+		
+		for child in valid_children :
+			self.writeTransitionsRecursively(child)
+				
+	#helper method
+	def writeFromTransitions(self, current_node): 
+		# get all transition out of this state
+		out_transitions = current_node.transitions
+		if len(out_transitions) == 0 :
+			return
+		
+		self.fOut.write('var enableds = new Array();')
+		for index, transition in enumerate(out_transitions, start=1):
+			self.writeTransitionCondition(transition, index)
+			
+		self.fOut.write("if (enableds.length > 1) {")
+		self.fOut.indent()
+		self.fOut.write('console.log("Runtime warning : indeterminism detected in a transition from node ' +  current_node.full_name+ '. Only the first in document order enabled transition is executed.")')
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.write()
+		self.fOut.write("if (enableds.length > 0) {")
+		self.fOut.indent()
+		self.fOut.write('var enabled = enableds[0];')	  
+			  
+		for index, transition in enumerate(out_transitions, start=1):
+			self.writeTransitionAction(transition, index)
+		
+		self.fOut.write('catched = true;')   
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.write()
+		
+	def visit_FormalEventParameter(self, formal_event_parameter):
+		self.fOut.extendWrite(formal_event_parameter.name)
+		
+	def writeFormalEventParameters(self, transition):
+		parameters = transition.getTrigger().getParameters()
+		if(len(parameters) > 0) :
+			self.fOut.write('var parameters = event.parameters;')
+			for index, parameter in enumerate(parameters):
+				self.fOut.write()
+				self.fOut.write("var ")
+				parameter.accept(self)
+				self.fOut.extendWrite(' = parameters[' + str(index) + '];')
+		
+		
+	def writeTransitionAction(self, transition, index):
+		if index > 1 :
+			self.fOut.write("else ")
+		else :
+			self.fOut.write()
+		self.fOut.extendWrite("if (enabled === " + str(index) + ") {")
+		self.fOut.indent()
+
+		# handle parameters to actually use them			 
+		self.writeFormalEventParameters(transition)
+		
+		exits = transition.getExitNodes()
+		
+		# write out exit actions
+		if not exits[-1].is_basic:
+			self.fOut.write("this.exit_" + exits[-1].full_name + "();")
+		else:
+			for node in exits:
+				if node.is_basic:
+					self.fOut.write("this.exit_" + node.full_name + "();")
+					
+		# write out trigger actions
+		transition.getAction().accept(self)
+		
+		for (entering_node, is_ending_node) in transition.getEnterNodes() : 
+			if is_ending_node :
+				if entering_node.is_composite:
+					self.fOut.write("this.enterDefault_" + entering_node.full_name + "();")
+				elif entering_node.is_history:
+					if (entering_node.is_history_deep) :
+						self.fOut.write("this.enterHistoryDeep_" + entering_node.parent.full_name + "();")
+					else :
+						self.fOut.write("this.enterHistoryShallow_" + entering_node.parent.full_name + "();")
+				else:
+					self.fOut.write("this.enter_" + entering_node.full_name + "();")
+			else :
+				if entering_node.is_composite:
+					self.fOut.write("this.enter_" + entering_node.full_name + "();")
+
+		self.fOut.dedent()
+		self.fOut.write("}")
+						
+	def writeTransitionCondition(self, transition, index):
+		trigger = transition.getTrigger()
+		if not trigger.isUC():  
+			self.fOut.write('if (event.name === "' + trigger.getEvent() + '"' + ((' && event.port === "' + trigger.getPort()+'"') if trigger.getPort() != "" else '') + ') {')
+			self.fOut.indent()   
+		# evaluate guard
+		if transition.hasGuard() :   
+			# handle parameters for guard evaluation	   
+			self.writeFormalEventParameters(transition)
+
+			self.fOut.write('if (')
+			transition.getGuard().accept(self)
+			self.fOut.extendWrite(') {')
+			self.fOut.indent()	
+			
+		self.fOut.write("enableds.push(" + str(index) + ");")
+
+		if transition.hasGuard() :
+			self.fOut.dedent()
+			self.fOut.write("}")
+		if not trigger.isUC() :
+			self.fOut.dedent()
+			self.fOut.write("}")
+		self.fOut.write()
+	
+	def visit_EnterAction(self, enter_method):
+		parent_node = enter_method.parent_node
+		self.writeMethodSignature(parent_node.statechart.class_obj.name, "enter_" + parent_node.full_name, [])
+		self.fOut.indent()
+		# take care of any AFTER events
+		for transition in parent_node.transitions :
+			trigger = transition.getTrigger()
+			if trigger.isAfter() :
+				self.fOut.write("this.timers[" + str(trigger.getAfterIndex()) + "] = ")
+				trigger.after.accept(self)
+				self.fOut.extendWrite(" * 1000.0; /* convert ms to s */")
+		if enter_method.action:
+			enter_method.action.accept(self)
+		self.fOut.write("this.current_state[this." + parent_node.parent.full_name + "].push(this." + parent_node.full_name + ");")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+		
+	#helper method
+	def writeEnterDefault(self, entered_node):
+		self.writeMethodSignature(entered_node.statechart.class_obj.name, "enterDefault_" + entered_node.full_name, [])
+		self.fOut.indent()
+		self.fOut.write("this.enter_" + entered_node.full_name + "();")
+		if entered_node.is_composite:
+			l = entered_node.defaults
+			for i in l:
+				if i.is_composite:
+					self.fOut.write("this.enterDefault_" + i.full_name + "();")
+				elif i.is_basic:
+					self.fOut.write("this.enter_" + i.full_name + "();")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+		 
+	def visit_ExitAction(self, exit_method):
+		exited_node = exit_method.parent_node
+		self.writeMethodSignature(exited_node.statechart.class_obj.name, "exit_" + exited_node.full_name, [])
+		self.fOut.indent()
+		
+		#If the exited node is composite take care of potential history and the leaving of descendants
+		if exited_node.is_composite :
+			#handle history
+			if exited_node.save_state_on_exit :
+				self.fOut.write("this.history_state[this." + exited_node.full_name + "] = this.current_state[this." + exited_node.full_name + "];")
+			
+			#Take care of leaving children
+			children = exited_node.children
+			if exited_node.is_parallel_state:
+				for child in children:
+					if not child.is_history :
+						self.fOut.write("this.exit_" + child.full_name + "();")
+			else:
+				for child in children:
+					if not child.is_history :
+						self.fOut.write("if (this.current_state[this." + exited_node.full_name + "].indexOf(this." + child.full_name +  ") !== -1) {")
+						self.fOut.indent()
+						self.fOut.write("this.exit_" + child.full_name + "();")
+						self.fOut.dedent()
+						self.fOut.write("}")
+		
+		
+		# take care of any AFTER events
+		for transition in exited_node.transitions :
+			trigger = transition.getTrigger()
+			if trigger.isAfter() :
+				self.fOut.write("delete this.timers[" + str(trigger.getAfterIndex()) + "];")
+				
+		#Execute user-defined exit action if present
+		if exit_method.action:
+			exit_method.action.accept(self)
+			
+		#Adjust state
+		self.fOut.write("this.current_state[this." + exited_node.parent.full_name + "] = new Array();") # SPECIAL CASE FOR ORTHOGONAL??
+		
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+		
+			
+	#helper method
+	def writeEnterHistory(self, entered_node, is_deep):
+		self.writeMethodSignature(entered_node.statechart.class_obj.name, "enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name, [])
+		self.fOut.indent()
+		self.fOut.write("if (this.history_state[this." + entered_node.full_name + "].length === 0) {")
+		self.fOut.indent()
+		defaults = entered_node.defaults
+
+		for node in defaults:
+			if node.is_basic :
+				self.fOut.write("this.enter_" + node.full_name + "();")
+			elif node.is_composite :
+				self.fOut.write("this.enterDefault_" + node.full_name + "();")
+
+		self.fOut.dedent()
+		self.fOut.write("} else {")
+		self.fOut.indent()
+		children = entered_node.children
+		if entered_node.is_parallel_state:
+			for child in children:
+				if not child.is_history :
+					self.fOut.write("this.enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + child.full_name + "();")
+		else:
+			for child in children:
+				if not child.is_history :
+					self.fOut.write("if (this.history_state[this." + entered_node.full_name + "].indexOf(this." + child.full_name + ") !== -1) {")
+					self.fOut.indent()
+					if child.is_composite:
+						if is_deep :
+							self.fOut.write("this.enter_" + child.full_name + "()")
+							self.fOut.write("this.enterHistoryDeep_" + child.full_name + "()")
+						else :
+							self.fOut.write("this.enterDefault_" + child.full_name + "()")
+					else:
+						self.fOut.write("this.enter_" + child.full_name + "()")
+					self.fOut.dedent()
+					self.fOut.write("}")
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+
+	def visit_StateChart(self, statechart):
+		self.fOut.write("// Statechart enter/exit action method(s) :")
+		self.fOut.write()
+		
+		#visit enter and exit action of children
+		for i in statechart.composites + statechart.basics:
+			if i is not statechart.root :
+				i.enter_action.accept(self)
+				i.exit_action.accept(self)
+
+		# write out statecharts methods for enter/exit state
+		if len(statechart.composites) > 1 :
+			self.fOut.write("// Statechart enter/exit default method(s) :")
+			self.fOut.write()
+			for i in statechart.composites :
+				if i is not statechart.root :
+					self.writeEnterDefault(i)
+
+		# write out statecharts methods for enter/exit history
+		if statechart.histories:
+			self.fOut.write("// Statechart enter/exit history method(s) :")
+			self.fOut.write()
+			for i in statechart.shallow_history_parents:
+				self.writeEnterHistory(i, False)
+			for i in statechart.deep_history_parents:
+				self.writeEnterHistory(i, True) 
+		   
+		   
+		self.fOut.write("// Statechart transitions :")	 
+		self.fOut.write()
+		self.writeTransitionsRecursively(statechart.root)			
+				
+		# write out transition function
+		self.fOut.write("// Execute transitions")
+		self.writeMethodSignature(statechart.class_obj.name, "transition", [FormalParameter("event", "Event", "new Event()")])
+		self.fOut.indent()
+		self.fOut.write("this.state_changed = this.transition_" + statechart.root.full_name + "(event);")
+		self.fOut.dedent()
+		self.fOut.write("};");
+		self.fOut.write()
+
+		# write out inState function
+		self.fOut.write("// inState method for statechart")
+		self.writeMethodSignature(statechart.class_obj.name, "inState", [FormalParameter("nodes", "Array")])
+		#self.fOut.write("def inState(self, nodes):")
+		self.fOut.indent()
+		self.fOut.write("for (var c in this.current_state) {")
+		self.fOut.indent()
+		self.fOut.write("if (!this.current_state.hasOwnProperty(c)) continue;")
+
+		self.fOut.write("var new_nodes = new Array();")
+		self.fOut.write("for (var n in nodes) {")
+		self.fOut.indent()
+		self.fOut.write("if (!nodes.hasOwnProperty(n)) continue;")
+		self.fOut.write("if (this.current_state[c].indexOf(nodes[n]) === -1) {")
+		self.fOut.indent()
+		self.fOut.write("new_nodes.push(nodes[n]);")
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.write("nodes = new_nodes;")
+		self.fOut.write("if (nodes.length === 0) {")
+		self.fOut.indent()
+		self.fOut.write("return true;")
+		self.fOut.dedent()
+
+		self.fOut.write("}")
+		self.fOut.dedent()
+		self.fOut.write("}")
+		self.fOut.write("return false;")
+		self.fOut.dedent()
+		self.fOut.write("};")
+		self.fOut.write()
+
+	def visit_ExpressionPartString(self, bare_string):
+		self.fOut.extendWrite(bare_string.string)
+		
+	def visit_SelfReference(self, self_reference):
+		self.fOut.extendWrite("this")
+		
+	def visit_StateReference(self, state_ref):
+		self.fOut.extendWrite("[" + ",".join(["this." + node.full_name for node in state_ref.getNodes()]) + "]")
+		
+	def visit_InStateCall(self, in_state_call):
+		self.fOut.extendWrite("this.inState(")
+		in_state_call.target.accept(self)
+		self.fOut.extendWrite(")")
+		
+	def visit_RaiseEvent(self, raise_event):
+		if raise_event.isNarrow() or raise_event.isBroad():
+			self.fOut.write('var send_event = new Event("' + raise_event.getEventName() + '", null, [')
+		elif raise_event.isLocal():
+			self.fOut.write('this.addEvent(new Event("' + raise_event.getEventName() + '", null, [')
+		elif raise_event.isOutput():
+			self.fOut.write('this.controller.outputEvent(new Event("' + raise_event.getEventName() + '", "' + raise_event.getPort() + '", [')
+		elif raise_event.isCD():
+			self.fOut.write('this.object_manager.addEvent(new Event("' + raise_event.getEventName() + '", null, [this, ')
+		first_param = True
+		for param in raise_event.getParameters() :
+			if first_param :
+				first_param = False
+			else :
+				self.fOut.extendWrite(',')
+			param.accept(self)
+		if raise_event.isNarrow():
+			self.fOut.extendWrite(']);')
+			self.fOut.write('this.object_manager.addEvent(new Event("narrow_cast", null, [this, ' + raise_event.getTarget() + ' , send_event]));')
+		elif raise_event.isBroad():
+			self.fOut.extendWrite(']);')
+			self.fOut.write('this.object_manager.addEvent(new Event("broad_cast", null, [send_event]));')
+		else :
+			self.fOut.extendWrite(']));')
+			
+	def visit_Script(self, script):
+		self.writeCodeCorrectIndent(script.code)
+		
+	def visit_Log(self, log):
+		self.fOut.write('console.log("' + log.message + '");')
+		
+	def visit_Assign(self, assign):
+		self.fOut.write()
+		assign.lvalue.accept(self)
+		self.fOut.extendWrite(" = ")
+		assign.expression.accept(self)
+	

+ 644 - 0
hybrid_server/python_sccd_compiler/old_generators/python_generator.py

@@ -0,0 +1,644 @@
+import time
+from constructs import FormalParameter
+from code_generation import CodeGenerator, Platforms
+
+class PythonGenerator(CodeGenerator):
+	
+	def __init__(self):
+		self.supported_platforms = [Platforms.Threads, Platforms.GameLoop]
+				
+	def visit_ClassDiagram(self, class_diagram):
+		self.fOut.write("# Statechart compiler by Glenn De Jonghe")
+		self.fOut.write("#")
+		self.fOut.write("# Date:   " + time.asctime())
+		if class_diagram.name or class_diagram.author or class_diagram.description:
+			self.fOut.write()
+		if class_diagram.author:
+			self.fOut.write("# Model author: " + class_diagram.author)
+		if class_diagram.name:
+			self.fOut.write("# Model name:   " + class_diagram.name)
+		if class_diagram.description.strip():
+			self.fOut.write("# Model description:")
+			self.fOut.write('"""')
+			self.fOut.indent()
+			self.fOut.write(class_diagram.description.strip())
+			self.fOut.dedent()
+			self.fOut.write('"""')
+		self.fOut.write()
+		
+		#Mandatory imports
+		self.fOut.write('from python_runtime.statecharts_core import ObjectManagerBase, Event, InstanceWrapper, RuntimeClassBase, Association')
+		#User imports
+		if class_diagram.top.strip():
+			self.writeCodeCorrectIndent(class_diagram.top)
+		self.fOut.write()
+		
+		#visit children
+		for c in class_diagram.classes :
+			c.accept(self)
+		 
+		#writing out ObjectManager
+		self.fOut.write('class ObjectManager (ObjectManagerBase):')
+		self.fOut.indent()
+		self.fOut.write('def __init__(self, controller):')
+		self.fOut.indent()
+		self.fOut.write("super(ObjectManager, self).__init__(controller)")
+		self.fOut.dedent()
+		self.fOut.write()
+		
+		self.fOut.write('def instantiate(self, class_name, construct_params):')
+		self.fOut.indent()
+		self.fOut.write("associations = []")
+		for index, c in enumerate(class_diagram.classes) :
+			if index == 0 : 
+				self.fOut.write()
+			else :
+				self.fOut.write('el')
+			self.fOut.extendWrite('if class_name == "' + c.name + '" :')
+			self.fOut.indent()
+			if c.statechart :
+				self.fOut.write('instance =  ' + c.name + '(self.controller, *construct_params)')
+			else :
+				self.fOut.write('instance =  ' + c.name + '(*construct_params)')
+			for a in c.associations :
+				a.accept(self)
+			self.fOut.dedent()
+		self.fOut.write('if instance:')
+		self.fOut.indent()
+		self.fOut.write('return InstanceWrapper(instance, associations)')
+		self.fOut.dedent()
+		self.fOut.write('else :')
+		self.fOut.indent()
+		self.fOut.write('return None')
+		self.fOut.dedent()
+		self.fOut.dedent()
+		self.fOut.dedent()
+		
+		self.fOut.write()
+		if self.platform == Platforms.Threads :
+			controller_sub_class = "ThreadsControllerBase"
+		elif self.platform == Platforms.GameLoop :
+			controller_sub_class = "GameLoopControllerBase"
+		self.fOut.write("from python_runtime.statecharts_core import " + controller_sub_class)
+
+		# write out controller
+		self.fOut.write("class Controller(" + controller_sub_class + "):")
+		self.fOut.indent()
+	
+		# write out __init__ method
+		if class_diagram.default_class.constructors :
+			for constructor in class_diagram.default_class.constructors :
+				self.writeControllerConstructor(class_diagram, constructor.parameters)
+		else :
+			self.writeControllerConstructor(class_diagram)
+
+		self.fOut.dedent()
+		self.fOut.write("def main():")
+		self.fOut.indent()
+		self.fOut.write("controller = Controller()")
+		self.fOut.write("controller.start()")
+		self.fOut.dedent()
+		self.fOut.write()
+	
+		self.fOut.write('if __name__ == "__main__":')
+		self.fOut.indent()
+		self.fOut.write("main()")
+		self.fOut.dedent()
+		self.fOut.write()
+		
+	#helper method
+	def writeControllerConstructor(self, class_diagram, parameters = []):
+		self.writeMethodSignature('__init__', parameters + [FormalParameter("keep_running", "", "True")])
+		self.fOut.indent()
+		self.fOut.write("super(Controller, self).__init__(ObjectManager(self), keep_running)")
+		for i in class_diagram.inports:
+			self.fOut.write('self.addInputPort("' + i + '")')
+		for i in class_diagram.outports:
+			self.fOut.write('self.addOutputPort("' + i + '")')
+		actual_parameters = [p.getIdent() for p in parameters]
+		self.fOut.write('self.object_manager.createInstance("'+ class_diagram.default_class.name +'", [' +  ', '.join(actual_parameters)+ '])')
+		self.fOut.write()
+		self.fOut.dedent()
+
+	def visit_Class(self, class_node):
+		"""
+		Generate code for Class construct
+		"""
+		self.fOut.write()
+		# take care of inheritance
+		if class_node.super_classes:
+			class_node.super_classes.append("RuntimeClassBase")
+			super_classes = []
+			for super_class in class_node.super_classes:
+				super_classes.append(super_class)
+			self.fOut.write("class " + class_node.name + "(" + ", ".join(super_classes) +  "):")
+		else:
+			self.fOut.write("class " + class_node.name + "(RuntimeClassBase):")
+
+		self.fOut.indent()
+		self.fOut.write()
+		
+		if class_node.statechart is not None:
+			# assign each node a unique ID
+			self.fOut.write("# Unique IDs for all statechart nodes")
+			for (i,node) in enumerate(class_node.statechart.composites + class_node.statechart.basics):
+				self.fOut.write(node.full_name + " = " + str(i))
+	
+			self.fOut.write()
+			self.writeMethodSignature("commonConstructor", [FormalParameter("controller", "", "None")])
+		else :
+			self.writeMethodSignature("commonConstructor")
+		self.fOut.indent()
+		self.fOut.write('"""Constructor part that is common for all constructors."""')
+		self.fOut.write("RuntimeClassBase.__init__(self)")
+
+		# write private input/output ports
+		self.fOut.write()
+		self.fOut.write("# User defined input ports")
+		self.fOut.write("self.inports = {}")
+		for p in class_node.inports:
+			self.fOut.write("self.inports[\""+p+"\"] = controller.addInputPort(\""+p+"\", self)")
+
+		# write attributes
+		if class_node.attributes:
+			self.fOut.write()
+			self.fOut.write("# User defined attributes")
+			for attribute in class_node.attributes:
+				if attribute.init_value is None :
+					self.fOut.write("self." +  attribute.name + " = None")
+				else :
+					self.fOut.write("self." +  attribute.name + " = " + attribute.init_value)	 
+			self.fOut.write()
+
+		# if there is a statechart
+		if class_node.statechart is not None:			
+			self.fOut.write("self.controller = controller")
+			self.fOut.write("self.object_manager = controller.getObjectManager()")
+			self.fOut.write("self.current_state = {}")
+			self.fOut.write("self.history_state = {}")
+			if class_node.statechart.nr_of_after_transitions:
+				self.fOut.write("self.timers = {}")
+			self.fOut.write()
+			self.fOut.write("#Initialize statechart :")
+			self.fOut.write()
+			
+			if class_node.statechart.histories:
+				for node in class_node.statechart.combined_history_parents:
+					self.fOut.write("self.history_state[" + class_node.name + "." + node.full_name + "] = []")
+				self.fOut.write()
+
+			for c in class_node.statechart.composites :
+				self.fOut.write("self.current_state[self." + c.full_name + "] = []")
+		
+		self.fOut.dedent()
+		self.fOut.write()
+		
+		self.writeMethodSignature("start")
+		self.fOut.indent()
+		self.fOut.write("super(" + class_node.name + ", self).start()")
+		if class_node.statechart:
+			for default_node in class_node.statechart.root.defaults:
+				if default_node.is_composite:
+					self.fOut.write("self.enterDefault_" + default_node.full_name + "()")
+				elif default_node.is_basic:
+					self.fOut.write("self.enter_" + default_node.full_name + "()")
+		self.fOut.dedent()
+		self.fOut.write()
+		
+		#visit children
+		for i in class_node.constructors :
+			i.accept(self)
+		for i in class_node.destructors :
+			i.accept(self)
+		for i in class_node.methods :
+			i.accept(self)
+		if class_node.statechart is not None:
+			class_node.statechart.accept(self)
+		  
+		# write out str method
+		self.fOut.dedent()
+
+	#helper method
+	def writeMethodSignature(self, name, parameters = []):
+		self.fOut.write("def " + name + "(self")		   
+		for param in parameters :
+			self.fOut.extendWrite(', ')
+			param.accept(self)
+		self.fOut.extendWrite("):")
+		
+	#helper method
+	def writeMethod(self, name, parameters, return_type, body):
+		self.writeMethodSignature(name, parameters)
+		self.fOut.indent()
+		if body.strip():
+			self.writeCodeCorrectIndent(body)
+		else:
+			self.fOut.write("return")
+		self.fOut.write()
+		self.fOut.dedent()
+		
+	def visit_FormalParameter(self, formal_parameter):
+		self.fOut.extendWrite(formal_parameter.getIdent())
+		if formal_parameter.hasDefault() :
+			self.fOut.extendWrite(" = " + formal_parameter.getDefault())
+		
+	def visit_Constructor(self, constructor):
+		self.fOut.write("#The actual constructor")
+		parameters =  [FormalParameter("controller", "", None)] + constructor.getParams()
+		self.writeMethodSignature("__init__", parameters)
+		self.fOut.indent()
+		if constructor.parent_class.statechart is not None :
+			self.fOut.write("self.commonConstructor(controller)")
+		else :
+			self.fOut.write("self.commonConstructor()")
+		if constructor.body :
+			self.fOut.write()
+			self.fOut.write("#constructor body (user-defined)")
+			self.writeCodeCorrectIndent(constructor.body)
+		self.fOut.dedent()
+		self.fOut.write()
+		
+	def visit_Destructor(self, destructor):
+		self.fOut.write("# User defined destructor")
+		self.writeMethod("__del__", [], "", destructor.body)
+		
+	def visit_Method(self, method):
+		self.fOut.write("# User defined method")
+		self.writeMethod(method.name, method.parameters, method.return_type, method.body)
+		
+	def visit_Association(self, association):
+		self.fOut.write('associations.append(Association("' + association.name + '", "' + association.to_class + '", ' + str(association.min) + ', ' + str(association.max) + '))')
+		
+	#helper method
+	def writeTransitionsRecursively(self, current_node):
+		self.fOut.write("def transition_" + current_node.full_name + "(self, event) :")
+		self.fOut.indent()
+		
+		valid_children = []
+		for child in current_node.children :
+			if child.is_composite or child.is_basic :
+				valid_children.append(child)  
+		 
+		self.fOut.write("catched = False")
+		do_dedent = False
+		if current_node.solves_conflict_outer :
+			self.writeFromTransitions(current_node)
+			if current_node.is_parallel_state or current_node.is_composite :
+				self.fOut.write("if not catched :")
+				self.fOut.indent()
+				do_dedent = True
+			
+		if current_node.is_parallel_state:
+			for child in valid_children :	 
+				self.fOut.write("catched = self.transition_" + child.full_name + "(event) or catched")
+		elif current_node.is_composite:
+			for i, child in enumerate(valid_children) :
+				if i > 0 :
+					self.fOut.write("el")
+				else :
+					self.fOut.write()
+				self.fOut.extendWrite("if self.current_state[self." + current_node.full_name + "][0] == self." + child.full_name + ":")
+				self.fOut.indent()
+				self.fOut.write("catched = self.transition_" + child.full_name + "(event)")
+				self.fOut.dedent()
+				
+		if current_node.solves_conflict_outer :
+			if do_dedent :
+				self.fOut.dedent()
+		elif len(current_node.transitions) > 0 :
+				self.fOut.write("if not catched :")
+				self.fOut.indent()
+				self.writeFromTransitions(current_node)
+				self.fOut.dedent()
+			
+		self.fOut.write("return catched")
+		self.fOut.dedent()
+		self.fOut.write();
+		
+		for child in valid_children :
+			self.writeTransitionsRecursively(child)
+				
+	#helper method
+	def writeFromTransitions(self, current_node): 
+		# get all transition out of this state
+		out_transitions = current_node.transitions
+		if len(out_transitions) == 0 :
+			return
+		
+		self.fOut.write('enableds = []')
+		for index, transition in enumerate(out_transitions, start=1):
+			self.writeTransitionCondition(transition, index)
+			
+		self.fOut.write("if len(enableds) > 1 :")
+		self.fOut.indent()
+		self.fOut.write('print "Runtime warning : indeterminism detected in a transition from node ' +  current_node.full_name+ '. Only the first in document order enabled transition is executed."')
+		self.fOut.dedent()
+		self.fOut.write()
+		self.fOut.write("if len(enableds) > 0 :")
+		self.fOut.indent()
+		self.fOut.write('enabled = enableds[0]')	  
+			  
+		for index, transition in enumerate(out_transitions, start=1):
+			self.writeTransitionAction(transition, index)
+		
+		self.fOut.write('catched = True')   
+		self.fOut.dedent()		 
+		self.fOut.write()
+		
+	def visit_FormalEventParameter(self, formal_event_parameter):
+		self.fOut.extendWrite(formal_event_parameter.name)
+		
+	def writeFormalEventParameters(self, transition):
+		parameters = transition.getTrigger().getParameters()
+		if(len(parameters) > 0) :
+			self.fOut.write('parameters = event.getParameters()')
+			for index, parameter in enumerate(parameters):
+				self.fOut.write()
+				parameter.accept(self)
+				self.fOut.extendWrite(' = parameters[' + str(index) + ']')
+		
+		
+	def writeTransitionAction(self, transition, index):
+		if index > 1 :
+			self.fOut.write("el")
+		else :
+			self.fOut.write()
+		self.fOut.extendWrite("if enabled == " + str(index) + " :")
+		self.fOut.indent()
+
+		# handle parameters to actually use them			 
+		self.writeFormalEventParameters(transition)
+		
+		exits = transition.getExitNodes()
+		
+		# write out exit actions
+		if not exits[-1].is_basic:
+			self.fOut.write("self.exit_" + exits[-1].full_name + "()")
+		else:
+			for node in exits:
+				if node.is_basic:
+					self.fOut.write("self.exit_" + node.full_name + "()")
+					
+		# write out trigger actions
+		transition.getAction().accept(self)
+		
+		for (entering_node, is_ending_node) in transition.getEnterNodes() : 
+			if is_ending_node :
+				if entering_node.is_composite:
+					self.fOut.write("self.enterDefault_" + entering_node.full_name + "()")
+				elif entering_node.is_history:
+					if (entering_node.is_history_deep) :
+						self.fOut.write("self.enterHistoryDeep_" + entering_node.parent.full_name + "()")
+					else :
+						self.fOut.write("self.enterHistoryShallow_" + entering_node.parent.full_name + "()")
+				else:
+					self.fOut.write("self.enter_" + entering_node.full_name + "()")
+			else :
+				if entering_node.is_composite:
+					self.fOut.write("self.enter_" + entering_node.full_name + "()")
+
+		self.fOut.dedent()
+						
+	def writeTransitionCondition(self, transition, index):
+		trigger = transition.getTrigger()
+		if not trigger.isUC():  
+			self.fOut.write('if event.name == "' + trigger.getEvent() + '" and event.getPort() == "' + trigger.getPort() + '" :')
+			self.fOut.indent()   
+		# evaluate guard
+		if transition.hasGuard() :   
+			# handle parameters for guard evaluation	   
+			self.writeFormalEventParameters(transition)
+
+			self.fOut.write('if ')
+			transition.getGuard().accept(self)
+			self.fOut.extendWrite(' :')
+			self.fOut.indent()	
+			
+		self.fOut.write("enableds.append(" + str(index) + ")")
+
+		if transition.hasGuard() :
+			self.fOut.dedent()
+		if not trigger.isUC() :
+			self.fOut.dedent()
+		self.fOut.write()
+	
+	def visit_EnterAction(self, enter_method):
+		parent_node = enter_method.parent_node
+		self.writeMethodSignature("enter_" + parent_node.full_name, [])
+		self.fOut.indent()
+		# take care of any AFTER events
+		for transition in parent_node.transitions :
+			trigger = transition.getTrigger()
+			if trigger.isAfter() :
+				self.fOut.write("self.timers[" + str(trigger.getAfterIndex()) + "] = ")
+				trigger.after.accept(self)
+		if enter_method.action:
+			enter_method.action.accept(self)
+		self.fOut.write("self.current_state[self." + parent_node.parent.full_name + "].append(self." + parent_node.full_name + ")")
+		self.fOut.dedent()
+		self.fOut.write()
+		
+	#helper method
+	def writeEnterDefault(self, entered_node):
+		self.writeMethodSignature("enterDefault_" + entered_node.full_name, [])
+		self.fOut.indent()
+		self.fOut.write("self.enter_" + entered_node.full_name + "()")
+		if entered_node.is_composite:
+			l = entered_node.defaults
+			for i in l:
+				if i.is_composite:
+					self.fOut.write("self.enterDefault_" + i.full_name + "()")
+				elif i.is_basic:
+					self.fOut.write("self.enter_" + i.full_name + "()")
+		self.fOut.dedent()
+		self.fOut.write()
+		 
+	def visit_ExitAction(self, exit_method):
+		exited_node = exit_method.parent_node
+		self.writeMethodSignature("exit_" + exited_node.full_name, [])
+		self.fOut.indent()
+		
+		#If the exited node is composite take care of potential history and the leaving of descendants
+		if exited_node.is_composite :
+			#handle history
+			if exited_node.save_state_on_exit :
+				self.fOut.write("self.history_state[self." + exited_node.full_name + "] = self.current_state[self." + exited_node.full_name + "]")
+			
+			#Take care of leaving children
+			children = exited_node.children
+			if exited_node.is_parallel_state:
+				for child in children:
+					if not child.is_history :
+						self.fOut.write("self.exit_" + child.full_name + "()")
+			else:
+				for child in children:
+					if not child.is_history :
+						self.fOut.write("if self." + child.full_name +  " in self.current_state[self." + exited_node.full_name + "] :")
+						self.fOut.indent()
+						self.fOut.write("self.exit_" + child.full_name + "()")
+						self.fOut.dedent()  
+		
+		
+		# take care of any AFTER events
+		for transition in exited_node.transitions :
+			trigger = transition.getTrigger()
+			if trigger.isAfter() :
+				self.fOut.write("self.timers.pop(" + str(trigger.getAfterIndex()) + ", None)")
+				
+		#Execute user-defined exit action if present
+		if exit_method.action:
+			exit_method.action.accept(self)
+			
+		#Adjust state
+		self.fOut.write("self.current_state[self." + exited_node.parent.full_name + "] = []") # SPECIAL CASE FOR ORTHOGONAL??
+		
+		self.fOut.dedent()
+		self.fOut.write()
+		
+			
+	#helper method
+	def writeEnterHistory(self, entered_node, is_deep):
+		self.writeMethodSignature("enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + entered_node.full_name, [])
+		self.fOut.indent()
+		self.fOut.write("if self.history_state[self." + entered_node.full_name + "] == []:")
+		self.fOut.indent()
+		defaults = entered_node.defaults
+
+		for node in defaults:
+			if node.is_basic :
+				self.fOut.write("self.enter_" + node.full_name + "()")
+			elif node.is_composite :
+				self.fOut.write("self.enterDefault_" + node.full_name + "()")
+
+		self.fOut.dedent()
+		self.fOut.write("else:")
+		self.fOut.indent()
+		children = entered_node.children
+		if entered_node.is_parallel_state:
+			for child in children:
+				if not child.is_history :
+					self.fOut.write("self.enterHistory" + ("Deep" if is_deep else "Shallow") + "_" + child.full_name + "()")
+		else:
+			for child in children:
+				if not child.is_history :
+					self.fOut.write("if self." + child.full_name + " in self.history_state[self." + entered_node.full_name + "] :")
+					self.fOut.indent()
+					if child.is_composite:
+						if is_deep :
+							self.fOut.write("self.enter_" + child.full_name + "()")
+							self.fOut.write("self.enterHistoryDeep_" + child.full_name + "()")
+						else :
+							self.fOut.write("self.enterDefault_" + child.full_name + "()")
+					else:
+						self.fOut.write("self.enter_" + child.full_name + "()")
+					self.fOut.dedent()
+		self.fOut.dedent()
+		self.fOut.dedent()
+		self.fOut.write()
+
+	def visit_StateChart(self, statechart):
+		self.fOut.write("# Statechart enter/exit action method(s) :")
+		self.fOut.write()
+		
+		#visit enter and exit action of children
+		for i in statechart.composites + statechart.basics:
+			if i is not statechart.root :
+				i.enter_action.accept(self)
+				i.exit_action.accept(self)
+
+		# write out statecharts methods for enter/exit state
+		if len(statechart.composites) > 1 :
+			self.fOut.write("#Statechart enter/exit default method(s) :")
+			self.fOut.write()
+			for i in statechart.composites :
+				if i is not statechart.root :
+					self.writeEnterDefault(i)
+
+		# write out statecharts methods for enter/exit history
+		if statechart.histories:
+			self.fOut.write("#Statechart enter/exit history method(s) :")
+			self.fOut.write()
+			for i in statechart.shallow_history_parents:
+				self.writeEnterHistory(i, False)
+			for i in statechart.deep_history_parents:
+				self.writeEnterHistory(i, True) 
+		   
+		   
+		self.fOut.write("#Statechart transitions :")	 
+		self.fOut.write()
+		self.writeTransitionsRecursively(statechart.root)			
+				
+		# write out transition function
+		self.fOut.write("# Execute transitions")
+		self.fOut.write("def transition(self, event = Event(\"\")):")
+		self.fOut.indent()
+		self.fOut.write("self.state_changed = self.transition_" + statechart.root.full_name + "(event)")
+		self.fOut.dedent()
+
+		# write out inState function
+		self.fOut.write("# inState method for statechart")
+		self.fOut.write("def inState(self, nodes):")
+		self.fOut.indent()
+		self.fOut.write("for actives in self.current_state.itervalues():")
+		self.fOut.indent()
+		self.fOut.write("nodes = [node for node in nodes if node not in actives]")
+		self.fOut.write("if not nodes :")
+		self.fOut.indent()
+		self.fOut.write("return True")
+		self.fOut.dedent()
+		self.fOut.dedent()
+		self.fOut.write("return False")
+		self.fOut.dedent()
+		self.fOut.write()
+		
+	def visit_ExpressionPartString(self, bare_string):
+		self.fOut.extendWrite(bare_string.string)
+		
+	def visit_SelfReference(self, self_reference):
+		self.fOut.extendWrite("self")
+		
+	def visit_StateReference(self, state_ref):
+		self.fOut.extendWrite("[" + ",".join(["self." + node.full_name for node in state_ref.getNodes()]) + "]")
+		
+	def visit_InStateCall(self, in_state_call):
+		self.fOut.extendWrite("self.inState(")
+		in_state_call.target.accept(self)
+		self.fOut.extendWrite(")")
+		
+	def visit_RaiseEvent(self, raise_event):
+		if raise_event.isNarrow() or raise_event.isBroad():
+			self.fOut.write('send_event = Event("' + raise_event.getEventName() + '", parameters = [')
+		elif raise_event.isLocal():
+			self.fOut.write('self.addEvent(Event("' + raise_event.getEventName() +'", parameters = [')
+		elif raise_event.isOutput():
+			self.fOut.write('self.controller.outputEvent(Event("' + raise_event.getEventName() + '", port="' + raise_event.getPort() + '", parameters = [')
+		elif raise_event.isCD():
+			self.fOut.write('self.object_manager.addEvent(Event("' + raise_event.getEventName() + '", parameters = [self, ')
+		first_param = True
+		for param in raise_event.getParameters() :
+			if first_param :
+				first_param = False
+			else :
+				self.fOut.extendWrite(',')
+			param.accept(self)
+		if raise_event.isNarrow():
+			self.fOut.extendWrite('])')
+			self.fOut.write('self.object_manager.addEvent(Event("narrow_cast", parameters = [self, ' + raise_event.getTarget() + ' , send_event]))')
+		elif raise_event.isBroad():
+			self.fOut.extendWrite('])')
+			self.fOut.write('self.object_manager.addEvent(Event("broad_cast", parameters = [send_event]))')
+		else :
+			self.fOut.extendWrite(']))')
+			
+	def visit_Script(self, script):
+		self.writeCodeCorrectIndent(script.code)
+		
+	def visit_Log(self, log):
+		self.fOut.write('print "' + log.message + '"')
+		
+	def visit_Assign(self, assign):
+		self.fOut.write()
+		assign.lvalue.accept(self)
+		self.fOut.extendWrite(" = ")
+		assign.expression.accept(self)
+	

+ 81 - 0
hybrid_server/python_sccd_compiler/path_calculator.py

@@ -0,0 +1,81 @@
+from compiler_exceptions import *
+from visitor import Visitor
+
+class PathCalculator(Visitor):
+	""" Computes the states that must be exited and entered for a specific transition if the system is to make
+		that transition. 
+	"""
+	
+	def visit_ClassDiagram(self, class_diagram): 
+		for c in class_diagram.classes :
+			c.accept(self)
+
+	def visit_Class(self, c):
+		if c.statechart:
+			c.statechart.accept(self)
+		
+	def visit_StateChart(self, statechart):
+		for node in statechart.basics + statechart.composites:
+			node.accept(self)
+					 
+	def visit_StateChartNode(self, node):
+		for transition in node.transitions :
+			transition.accept(self)
+			
+	def visit_StateChartTransition(self, transition):
+		#Find the scope of the transition (lowest common proper ancestor)
+		#TODO: Could it be made more efficient if we calculated the LCA from the source node and just one of the target nodes?
+		LCA = self.calculateLCA(transition)
+		
+		if LCA == None:
+			#raise CompilerException("Transision with source " + transition.parent_node.name + " and target " + transition.target_nodes + " has no lowest common ancestor node.")
+			raise CompilerException("Transision with source '" + transition.parent_node.name + "' and target + '" + transition.target_string + "' has no lowest common ancestor node.")
+
+		#Calculate exit nodes
+		transition.exit_nodes = [transition.parent_node]
+		for node in transition.parent_node.getAncestors() :
+			if (node == LCA) :
+				break
+			transition.exit_nodes.append(node)
+	   
+		#Calculate enter nodes
+		transition.enter_nodes = []
+		
+		#we then add the branching paths to the other nodes
+		for target_node in transition.target.target_nodes :
+			to_append_list = [(target_node, True)]
+			for anc in target_node.getAncestors() :
+				if anc == LCA : #If we reach the LCA in the ancestor hierarchy we break
+					break;
+				to_add = True;  #boolean value to see if the current ancestor should be added to the result
+				for enter_node_entry in transition.enter_nodes :
+					if anc == enter_node_entry[0] :
+						to_add = False #If we reach an ancestor in the hierarchy that is already listed as enter node, we don't add and break
+						break
+				if to_add:
+					to_append_list.append((anc, False)) #Only the first from the ancestor list should get True
+				else :
+					break
+					
+			to_append_list.reverse() #the enter sequence should be in the reverse order of the ancestor hierarchy
+			transition.enter_nodes.extend(to_append_list)
+
+		# Calculate arena
+		current = LCA
+		while not current.is_composite:
+			current = current.parent
+		transition.arena = current
+
+	def calculateLCA(self, transition):
+		"""
+		Calculates the lowest common ancestor of a transition
+		""" 
+		for anc in transition.parent_node.getAncestors() :
+			all_descendants = True 
+			for node in transition.target.getNodes() :
+				if not node.isDescendantOf(anc) :
+					all_descendants = False
+					break
+			if all_descendants :
+				return anc
+		return None

+ 353 - 0
hybrid_server/python_sccd_compiler/python_writer.py

@@ -0,0 +1,353 @@
+from generic_language_constructs import *
+
+class PythonWriter(GenericWriterBase):
+	def __init__(self, outputter):
+		self.out = outputter
+
+
+	def writeComment(self, text):
+		self.out.write("# " + text)
+
+	def writeMultiLineComment(self, text):
+		self.out.write("\"\"\"\n" + text + "\n\"\"\"")
+
+	def visit_AndOperator(self, a):
+		self.out.extendWrite(" and ")
+
+	def visit_ArrayContains(self, a):
+		array = a.getArrayExpression()
+		el = a.getElementExpression()
+
+		el.accept(self)
+		self.out.extendWrite(" in ")
+		array.accept(self)
+
+	def visit_ArrayExpression(self, a):
+		self.out.extendWrite("[")
+		self.writeCommaSeparated(a.getElements())
+		self.out.extendWrite("]")
+
+	def visit_ArrayIndexOf(self, a):
+		array = a.getArrayExpression()
+		el = a.getElementExpression()
+
+		array.accept(self)
+		self.out.extendWrite(".index(")
+		el.accept(self)
+		self.out.extendWrite(")")
+
+	def visit_ArrayLength(self, a):
+		self.out.extendWrite("len(")
+		a.getArrayExpression().accept(self)
+		self.out.extendWrite(")")
+
+	def visit_ArrayPushBack(self, a):
+		array = a.getArrayExpression()
+		el = a.getElementExpression()
+
+		array.accept(self)
+		self.out.extendWrite(".append(")
+		el.accept(self)
+		self.out.extendWrite(")")
+
+	def visit_AST(self, ast):
+		self.writeAll(ast.getEntries())
+
+	def visit_Block(self, b):
+		self.out.indent()
+		self.writeAll(b.getEntries())
+		if b.isEmpty():
+			self.out.write("pass")
+		self.out.dedent()
+
+	def visit_BreakStatement(self, b):
+		self.out.write("break")
+
+	def visit_Class(self, c):
+		class_name = c.getIdentifier()
+		constructor = c.getConstructor()
+		super_classes = c.getSuperClassIdentifierList()
+		description = c.getDescription()
+
+		self.out.write()
+		if description:
+			self.writeComment(description)
+		self.out.write("class " + class_name)
+		if super_classes:
+			self.out.extendWrite("(" + ", ".join(super_classes) + ")")
+		self.out.extendWrite(":")
+		self.out.indent()
+		constructor.accept(self)
+		self.writeAll(c.getMembers())
+		self.out.dedent()
+
+	def visit_Constructor(self, constructor):
+		#class_name = constructor.getClass().getIdentifier()
+		parameters = constructor.getFormalParameters()
+		body = constructor.getBody()
+
+		self.out.write("def __init__")
+		parameters.accept(self)
+		self.out.extendWrite(":")
+		body.accept(self)
+
+	def visit_Destructor(self, destructor):
+		#class_name = destructor.getClass().getIdentifier()
+		parameters = destructor.getFormalParameters()
+		body = destructor.getBody()
+
+		self.out.write("def __del__")
+		parameters.accept(self)
+		self.out.extendWrite(":")
+		body.accept(self)
+
+	def visit_ElseStatement(self, else_stmt):
+		self.out.write("else:")
+		else_stmt.getBody().accept(self)
+
+	def visit_ElseIfStatement(self, else_if):
+		condition = else_if.getCondition()
+		body = else_if.getBody()
+
+		if else_if.isFirst():
+			self.out.write("if ")
+		else:
+			self.out.write("elif ")
+		condition.accept(self)
+		self.out.extendWrite(":")
+		body.accept(self)
+
+	def visit_EqualsOperator(self, e):
+		self.out.extendWrite(" == ")
+
+	def visit_ExpressionStatement(self, stmt):
+		self.out.write() # expressions don't begin with a newline
+		stmt.expression.accept(self)
+
+	def visit_FalseExpression(self, f):
+		self.out.extendWrite("False")
+
+	def visit_FormalParameter(self, parameter):
+		self.out.extendWrite(parameter.getIdentifier())
+		if parameter.getDefaultValue():
+			self.out.extendWrite(" = None") # correct default value will be assigned in function body
+
+	def visit_FormalParameters(self, p):
+		params = [Literal("self")] + p.getParameterList()
+		self.writeTuple(params)
+
+	def visit_ForLoopCurrentElement(self, el):
+		#collection = el.getCollectionExpression()
+		iterator = el.getIteratorIdentifier()
+
+		self.out.extendWrite(iterator)
+
+	def visit_ForLoopIterateArray(self, loop):
+		collection = loop.getCollectionExpression()
+		iterator = loop.getIteratorIdentifier()
+		body = loop.getBody()
+
+		self.out.write("for " + iterator + " in ")
+		collection.accept(self)
+		self.out.extendWrite(":")
+		body.accept(self)
+
+	def visit_ForLoopIterateMapValues(self, loop):
+		collection = loop.getCollectionExpression()
+		iterator = loop.getIteratorIdentifier()
+		body = loop.getBody()
+
+		self.out.write("for " + iterator + " in ")
+		collection.accept(self)
+		self.out.extendWrite(".itervalues():")
+		body.accept(self)
+
+	def visit_IfStatement(self, if_stmt):
+		condition = if_stmt.getCondition()
+		body = if_stmt.getBody()
+
+		self.out.write("if ")
+		condition.accept(self)
+		self.out.extendWrite(":")
+		body.accept(self)
+
+	def visit_IncludeStatement(self, i):
+		module_path = i.getModulePath()
+		imported_symbols = i.getImportedSymbols()
+
+		self.out.write("from ")
+		for j in range(len(module_path)):
+			if j != 0:
+				self.out.extendWrite(".")
+			module_path[j].accept(self)
+		self.out.extendWrite(" import ")
+		if imported_symbols:
+			self.writeCommaSeparated(imported_symbols)
+		else:
+			self.out.extendWrite("*")
+
+	def visit_LocalVariableDeclaration(self, decl):
+		identifier = decl.getIdentifier()
+		init_value = decl.getInitValue()
+
+		self.out.extendWrite(decl.getIdentifier())
+		if init_value:
+			self.out.extendWrite(" = ")
+			init_value.accept(self)
+
+	def visit_LogStatement(self, l):
+		self.out.write("print \"" + l.getMessage() + "\"")
+
+	def visit_MapExpression(self, m):
+		elements = m.getElements()
+		self.out.extendWrite("{")
+		keys = elements.keys()
+		for i in range(len(keys)):
+			if i != 0:
+				self.out.extendWrite(", ")			
+			self.out.extendWrite(keys[i] + " : ")
+			self.out.extendWrite(" : ")
+			elements[keys[i]].accept(self)
+		self.out.extendWrite("}")
+
+	def visit_MapIndexedExpression(self, i):
+		m = i.getMapExpression()
+		key = i.getKeyExpression()
+
+		m.accept(self)
+		self.out.extendWrite("[")
+		key.accept(self)
+		self.out.extendWrite("]")
+
+	def visit_MapRemoveElement(self, stmt):
+		map_expr = stmt.getMapExpression()
+		key_expr = stmt.getKeyExpression()
+
+		self.out.write() # this is a statement, not an expression
+		map_expr.accept(self)
+		self.out.extendWrite(".pop(")
+		key_expr.accept(self)
+		self.out.extendWrite(", None)")
+
+	def visit_Method(self, method):
+		class_name = method.getClass().getIdentifier()
+		method_name = method.getIdentifier()
+		description = method.getDescription()
+		body = method.getBody()
+		parameters = method.getFormalParameters()
+
+		self.out.write()
+		if description:
+			self.writeComment(description)
+		self.out.write("def " + method_name + "")
+		parameters.accept(self)
+		self.out.extendWrite(":")
+		body.accept(self)
+
+	def visit_MethodBody(self, body):
+		method = body.getMethod()
+		formal_parameters = method.getFormalParameters()
+		formal_parameter_list = formal_parameters.getParameterList()
+
+		self.out.indent()
+		# check for undefined parameters and replace them with default values
+		for p in formal_parameter_list:
+			p_id = p.getIdentifier()
+			p_default = p.getDefaultValue()
+			if p_default:
+				self.out.write("if " + p_id + " == None: " + p_id + " = ")
+				p_default.accept(self)
+		self.writeAll(body.getEntries())
+		if body.isEmpty():
+			self.out.write("pass")
+		self.out.dedent()
+
+	def visit_NewExpression(self, new):
+		type_expr = new.getTypeExpression()
+		params = new.getActualParameters()
+
+		type_expr.accept(self)
+		params.accept(self)
+
+	def visit_NoneExpression(self, n):
+		self.out.extendWrite("None")
+
+	def visit_NotOperator(self, n):
+		self.out.extendWrite("not ")
+
+	def visit_OrOperator(self, o):
+		self.out.extendWrite(" or ")
+
+	def visit_Package(self, package):
+		name = package.getIdentifier()
+		description = package.getDescription()
+
+		self.writeComment("package \"" + name + "\"")
+		if description:
+			self.writeComment(description)
+		self.writeAll(package.getDeclarations())
+
+	def visit_ReturnStatement(self, r):
+		self.out.write("return ")
+		r.getExpression().accept(self)
+
+	def visit_RuntimeModuleIdentifier(self, r):
+		self.out.extendWrite("python_runtime")
+
+	def visit_SelfExpression(self, s):
+		self.out.extendWrite("self")
+
+	def visit_StaticAttribute(self, attr):
+		name = attr.getIdentifier()
+		init_value = attr.getInitValue()
+		#class_name = attr.getClass().getIdentifier()
+
+		if init_value:
+			self.out.write(name + " = ")
+			init_value.accept(self)
+		else:
+			self.out.write(name + " = None")
+
+	def visit_SuperClassConstructorCall(self, call):
+		super_class = call.getSuperClassIdentifier()
+		params = call.getActualParameters()
+		param_list = [Literal("self")] + params.getParameterList()
+		params = ActualParameters(param_list)
+
+		self.out.extendWrite(super_class)
+		self.out.extendWrite(".__init__")
+		params.accept(self)
+
+	def visit_SuperClassDestructorCall(self, call):
+		super_class = call.getSuperClassIdentifier()
+		params = call.getActualParameters()
+		param_list = [Literal("self")] + params.getParameterList()
+		params = ActualParameters(param_list)
+
+		self.out.extendWrite("if hasattr(")
+		self.out.extendWrite(super_class)
+		self.out.extendWrite(", \"__del__\"):")
+		self.out.indent()
+		self.out.write(super_class)
+		self.out.extendWrite(".__del__")
+		params.accept(self)
+		self.out.dedent()
+
+	def visit_SuperClassMethodCall(self, call):
+		super_class = call.getSuperClassIdentifier()
+		method_name = call.getMethodIdentifier()
+		params = call.getActualParameters()
+		param_list = [Literal("self")] + params.getParameterList()
+		params = ActualParameters(param_list)
+
+		self.out.extendWrite(super_class + "." + method_name)
+		params.accept(self)
+
+	def visit_ThrowExceptionStatement(self, stmt):
+		self.out.write("raise Exception(")
+		stmt.getExpression().accept(self)
+		self.out.extendWrite(")")
+
+	def visit_TrueExpression(self, t):
+		self.out.extendWrite("True")
+

Plik diff jest za duży
+ 1131 - 0
hybrid_server/python_sccd_compiler/sccd_constructs.py


+ 129 - 0
hybrid_server/python_sccd_compiler/sccdc.py

@@ -0,0 +1,129 @@
+import argparse
+import os
+import sys
+from generic_generator import GenericGenerator, Platforms
+from utils import Enum, Logger, FileWriter
+from super_class_linker import SuperClassLinker
+from state_linker import StateLinker
+from path_calculator import PathCalculator
+from sccd_constructs import ClassDiagram
+from generic_language_constructs import GenericConstruct
+from compiler_exceptions import CompilerException
+
+from javascript_writer import JavascriptWriter
+from python_writer import PythonWriter
+
+def generate(input_file, output_file, target_language, platform):
+	sccd = xmlToSccd(input_file)
+
+	if not target_language:
+		if sccd.language:
+			target_language = sccd.language
+		else:
+			target_language = "python" # default
+	elif sccd.language and target_language != sccd.language:
+		Logger.showError("Diagram specifies target language as \"" + sccd.language + "\", but language option of compiler has been set to \"" + target_language + "\". No output has been generated.")
+		return
+
+	if target_language == "python" and not output_file.endswith(".py") :
+		output_file += ".py"
+	elif target_language == "javascript" and not output_file.endswith(".js") :
+		output_file += ".js"
+
+	generic = sccdToGeneric(sccd, platform)
+	genericToTarget(generic, target_language, output_file)
+
+def xmlToSccd(xml_file):
+	cd = ClassDiagram(xml_file) # create AST
+	cd.accept(SuperClassLinker())
+	#SuperClassLinker().visit(cd) # visitor linking super classs references
+	StateLinker().visit(cd) # visitor fixing state references
+	PathCalculator().visit(cd) # visitor calculating paths
+	return cd
+	
+def sccdToGeneric(sccd, platform):
+	succesfull_generation = False
+	generator = GenericGenerator(platform)
+	sccd.accept(generator)
+	generic = generator.get()
+	Logger.showInfo("Classes <" + ", ".join(sccd.class_names) + "> have been converted to generic language constructs.")
+	return generic
+
+def genericToTarget(generic, target_language, output_file):
+	try:
+		f = FileWriter(output_file)
+		if target_language == "javascript":
+			writer = JavascriptWriter(f)
+		elif target_language == "python":
+			writer = PythonWriter(f)
+		else:
+			raise Exception("Language not supported")
+		generic.accept(writer)
+		Logger.showInfo("Generic language constructs have been converted to target language constructs and have been written to file '" + output_file + "'.")
+	finally:
+		f.close()
+		
+def main():
+	parser = argparse.ArgumentParser()
+	parser.add_argument('input', help='The path to the XML file to be compiled.')
+	parser.add_argument('-o', '--output', type=str, help='The path to the generated code. Defaults to the same name as the input file but with matching extension.')
+	parser.add_argument('-v', '--verbose', type=int, help='2 = all output; 1 = only warnings and errors; 0 = only errors; -1 = no output.  Defaults to 2.', default = 2)
+	parser.add_argument('-p', '--platform', type=str, help="Let the compiled code run on top of threads, gameloop or eventloop. The default is eventloop.")
+	parser.add_argument('-l', '--language', type=str, help='Target language, either "javascript" or "python". Defaults to the latter.')
+	
+	args = vars(parser.parse_args())
+	#Set verbose
+	if args['verbose'] is not None:
+		if args['verbose'] in [-1, 0,1,2] :
+			Logger.verbose = args['verbose']
+		else :
+			Logger.showError("Invalid verbose argument.")
+	else :
+		Logger.verbose = 2
+
+	#Set source file
+	source = args['input']
+	if not source.endswith(".xml") :
+		Logger.showError("Input file not valid.")
+		return
+	
+	#Set target language
+	if args['language'] :
+		target_language = args['language']
+	else :
+		target_language = ""
+
+	#Set output file
+	if args['output'] :
+		output = args['output']
+	else:
+		output = os.path.splitext(os.path.split(source)[1])[0]
+		
+	#Set platform	
+	if args['platform'] :
+		args['platform'] = args['platform'].lower()
+		if args['platform'] == "threads" :
+			platform = Platforms.Threads
+		elif args['platform'] == "gameloop" :
+			platform = Platforms.GameLoop
+		elif args['platform'] == "eventloop" :
+			platform = Platforms.EventLoop
+		else :
+			Logger.showError("Invalid platform.")
+			return		  
+	else :
+		platform = Platforms.EventLoop
+		
+	#Compile	
+	try :
+		generate(source, output, target_language, platform)
+	except CompilerException as exception :
+		Logger.showError(str(exception));
+		return 1
+
+	return 0
+
+if __name__ == "__main__":
+	sys.exit(main())
+
+

+ 156 - 0
hybrid_server/python_sccd_compiler/state_linker.py

@@ -0,0 +1,156 @@
+from visitor import Visitor
+from sccd_constructs import INSTATE_SEQ
+from compiler_exceptions import CompilerException
+from lexer import Lexer, Token, TokenType
+
+class StateReferenceException(CompilerException):
+	pass
+
+class StateLinker(Visitor):
+	
+	def __init__(self):
+		self.visiting_statechart = None
+		self.visiting_node = None
+		self.lexer = Lexer()
+	
+	def visit_ClassDiagram(self, class_diagram): 
+		for c in class_diagram.classes :
+			c.accept(self)
+
+	def visit_Class(self, c):
+		if c.statechart:
+			c.statechart.accept(self)
+		
+	def visit_StateChart(self, statechart):
+		self.visiting_statechart = statechart
+		for node in statechart.basics + statechart.composites:
+			node.accept(self)
+					 
+	def visit_StateChartNode(self, node):
+		self.visiting_node = node
+		node.enter_action.accept(self)
+		node.exit_action.accept(self)
+		for transition in node.transitions :
+			transition.accept(self)
+			
+	def visit_StateChartTransition(self, transition):
+		try :
+			transition.target.accept(self)
+		except StateReferenceException as exception :
+			raise StateReferenceException("Transition from <" + self.visiting_node.full_name + "> has invalid target. " + exception.message)
+		try :
+			transition.action.accept(self)
+		except StateReferenceException as exception :
+			raise StateReferenceException("Transition from <" + self.visiting_node.full_name + "> has invalid action. " + exception.message)
+		try :
+			if transition.guard :
+				transition.guard.accept(self)
+		except StateReferenceException as exception :
+			raise StateReferenceException("Transition from <" + self.visiting_node.full_name  + "> has invalid guard. " + exception.message)
+		
+	def visit_StateReference(self, state_reference):
+		state_reference.target_nodes = []
+		
+		current_node = None #Will be used to find the target state(s)
+		split_stack = [] #used for branching
+
+		self.lexer.input(state_reference.path_string)
+
+		for token in self.lexer.tokens() :
+			
+			if current_node == None : #current_node is not set yet or has been reset, the CHILD token can now have a special meaning
+				if token.type == TokenType.SLASH :
+					#Root detected
+					current_node = self.visiting_statechart.root
+					#Token consumed so continue
+					continue
+				else :
+					current_node = self.visiting_node
+					
+			if token.type == TokenType.DOT :
+				#Advance to next token
+				token = self.lexer.nextToken()
+				
+				if token is None or token.type == TokenType.SLASH :
+					#CURRENT operator "." detected
+					continue
+				elif token.type == TokenType.DOT :
+					#Advance to next token
+					token = self.lexer.nextToken()
+					if token is None or token.type == TokenType.SLASH :
+						#PARENT operator ".." detected
+						current_node = current_node.parent
+						if current_node is None :
+							raise StateReferenceException("Illegal use of PARENT \"..\" operator at position " + str(token.pos) + " in state reference. Root of statechart reached.")
+					
+					else :
+						raise StateReferenceException("Illegal use of PARENT \"..\" operator at position " + str(token.pos) + " in state reference.")
+	
+				else :
+					raise StateReferenceException("Illegal use of CURRENT \".\" operator at position " + str(token.pos) + " in state reference.")
+					
+			elif token.type == TokenType.SLASH :
+				continue
+			elif token.type == TokenType.WORD :
+				#try to advance to next child state
+				cname = token.val
+				found = False
+				for child in current_node.children :
+					if child.name == cname : 
+						found = True
+						current_node = child
+						break
+				if not found :
+					raise StateReferenceException("Refering to non exiting node at posisition " + str(token.pos) + " in state reference.")
+			elif token.type == TokenType.LBRACKET :
+				split_stack.append(current_node)
+			elif token.type == TokenType.RBRACKET :
+				if len(split_stack) > 0 :
+					split_stack.pop()
+				else :
+					raise StateReferenceException("Invalid token at position " + str(token.pos) + " in state reference.")
+			elif token.type == TokenType.COMMA :
+				state_reference.target_nodes.append(current_node)
+				if len(split_stack) > 0 :
+					current_node = split_stack[-1]
+				else :
+					current_node = None
+			
+			else :
+				raise StateReferenceException("Invalid token at position " + str(token.pos) + " in state reference.")
+		
+		if (len(split_stack) != 0) or (current_node is None) : #RB missing or extra COMMA
+			raise StateReferenceException("State reference ends unexpectedly.")
+		
+		#TODO better validation of the target! When is it a valid state configuration?
+		for node in state_reference.target_nodes :
+			if current_node == node :
+				raise StateReferenceException("A state reference can't reference the same node more than once.")
+			if node.isDescendantOrAncestorOf(current_node) :
+				raise StateReferenceException("A state reference can't reference a node and one of its descendants.");
+		
+		state_reference.target_nodes.append(current_node)
+			
+		if len(state_reference.target_nodes) == 0 :
+			raise StateReferenceException("Meaningless state reference.")
+
+	def visit_Expression(self, expression):
+		for part in expression.expression_parts :
+			part.accept(self)
+
+	def visit_EnterExitAction(self, action):
+		if action.action :
+			action.action.accept(self)
+			
+	def visit_Action(self, action):
+		for subaction in action.sub_actions :
+			subaction.accept(self)
+			
+	def visit_InStateCall(self, call):
+		try :
+			call.target.accept(self)
+		except StateReferenceException :
+			raise StateReferenceException("Invalid state reference for " + INSTATE_SEQ + " call.")
+		
+	def visit_Assign(self, assign):
+		assign.expression.accept(self)

+ 222 - 0
hybrid_server/python_sccd_compiler/stateful_writer.py

@@ -0,0 +1,222 @@
+# Used by generic_generator to create an AST of generic language constructs
+# while visiting an AST of SCCD constructs
+
+from generic_language_constructs import *
+
+class ExpressionWrapper(SimpleExpression, AbstractList):
+	def __init__(self, expr = None):
+		self.expr = expr
+
+	def add(self, expr):
+		if self.expr:
+			raise Exception("Expression can only be set once.")
+		self.expr = expr
+
+	def get(self):
+		return self.expr
+
+
+class StatefulWriter:
+
+	def __init__(self):
+		self.ast = AST()
+		self.last = None
+		self.stack = [self.ast]
+
+	def get(self):
+		return self.stack[-1]
+
+	def startRecordingExpression(self):
+		self.stack.append(ExpressionWrapper())
+
+	def stopRecordingExpression(self):
+		self.last = self.stack.pop()
+		if not isinstance(self.last, ExpressionWrapper):
+			raise Exception("Assymetry detected.")
+		return self.last.get()
+
+
+	def add(self, block_entry):
+		self.get().add(block_entry)
+
+	#### SHORTHANDS ####
+
+	def addActualParameter(self, expr):
+		self.get().getActualParameters().add(expr)
+
+	def addAssignment(self, lhs, rhs):
+		self.add(AssignmentExpression(lhs, rhs))
+
+	def addInclude(self, module_path, symbols = None):
+		self.add(IncludeStatement(module_path, symbols))
+
+	def addComment(self, comment):
+		self.add(SingleLineComment(comment))
+
+	def addFormalParameter(self, parameter, default_value = None):
+		self.get().getFormalParameters().add(FormalParameter(parameter, default_value))
+
+	def addMultiLineComment(self, comment):
+		self.add(MultiLineComment(comment))
+
+	def addRawCode(self, raw):
+		self.add(RawCode(raw))
+
+	def addStaticAttribute(self, identifier, init_value):
+		self.add(StaticAttribute(self.get(), identifier, init_value))
+
+	def addVSpace(self):
+		self.add(VSpace())
+
+
+	#### STATEFUL OPERATIONS ####
+
+	def begin(self, generic_construct):
+		self.add(generic_construct)
+		self.stack.append(generic_construct)
+
+	def beginArray(self):
+		self.begin(ArrayExpression())
+
+	def beginClass(self, class_name, super_class_names = None, comment = None):
+		self.begin(Class(class_name, super_class_names, comment))
+
+	def beginConstructor(self):
+		c = self.get().getConstructor()
+		self.stack.append(c)
+
+	def beginDestructor(self):
+		d = self.get().getDestructor()
+		self.stack.append(d)
+
+	def beginElse(self):
+		self.begin(ElseStatement())
+
+	def beginElseIf(self, condition):
+		self.begin(ElseIfStatement(condition, not isinstance(self.last, ElseIfStatement)))
+
+	def beginForLoopIterateArray(self, array_expr, iterator_identifier):
+		f = ForLoopIterateArray(array_expr, iterator_identifier)
+		self.get().add(f)
+		self.stack.append(f.getBody())
+
+	def beginForLoopIterateMapValues(self, map_expr, iterator_identifier):
+		f = ForLoopIterateMapValues(map_expr, iterator_identifier)
+		self.get().add(f)
+		self.stack.append(f.getBody())
+
+	def beginFunctionCall(self, function_expr):
+		f = FunctionCall(function_expr)
+		self.get().add(f)
+		self.stack.append(f)
+
+	def beginGlue(self):
+		g = Glue()
+		self.get().add(g)
+		self.stack.append(g)
+
+	def beginIf(self, condition):
+		self.begin(IfStatement(condition))
+
+
+	def beginMethod(self, name, comment = None):
+		m = Method(self.get(), name, comment)
+		self.get().add(m)
+		self.stack.append(m)
+
+	def beginMethodBody(self):
+		b = self.get().getBody()
+		self.stack.append(b)
+
+	def beginPackage(self, package_name):
+		p = Package(package_name)
+		self.get().add(p)
+		self.stack.append(p)
+
+	def beginSuperClassConstructorCall(self, super_class_identifier):
+		c = SuperClassConstructorCall(super_class_identifier)
+		self.get().add(c)
+		self.stack.append(c)
+
+	def beginSuperClassDestructorCall(self, super_class_identifier):
+		c = SuperClassDestructorCall(super_class_identifier)
+		self.get().add(c)
+		self.stack.append(c)
+
+	def beginSuperClassMethodCall(self, super_class_identifier, method_identifier):
+		c = SuperClassMethodCall(super_class_identifier, method_identifier)
+		self.get().add(c)
+		self.stack.append(c)
+
+
+	def end(self):
+		self.stack.pop()
+
+	def endArray(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, ArrayExpression)
+
+	def endClass(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, Class)
+
+	def endConstructor(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, Constructor)
+
+	def endDestructor(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, Destructor)
+
+	def endElse(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, ElseStatement)
+
+	def endElseIf(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, ElseIfStatement)
+
+	def endForLoopIterateArray(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, ForLoopBody)
+
+	def endForLoopIterateMapValues(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, ForLoopBody)
+
+	def endFunctionCall(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, FunctionCall)
+
+	def endGlue(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, Glue)
+
+	def endIf(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, IfStatement)
+
+	def endMethod(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, Method)
+
+	def endMethodBody(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, MethodBody)
+
+	def endPackage(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, Package)
+
+	def endSuperClassConstructorCall(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, SuperClassConstructorCall)
+
+	def endSuperClassDestructorCall(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, SuperClassDestructorCall)
+
+	def endSuperClassMethodCall(self):
+		self.last = self.stack.pop()
+		assert isinstance(self.last, SuperClassMethodCall)
+

+ 52 - 0
hybrid_server/python_sccd_compiler/super_class_linker.py

@@ -0,0 +1,52 @@
+from compiler_exceptions import *
+from utils import Logger
+from visitor import Visitor
+
+class SuperClassLinker(Visitor):
+	""" Computes the states that must be exited and entered for a specific transition if the system is to make
+		that transition. 
+	"""
+	
+	def visit_ClassDiagram(self, class_diagram): 
+		for c in class_diagram.classes :
+			c.accept(self)
+
+	def visit_Class(self, c):
+		# replace super class names by super class objects
+		for s in c.super_classes:
+			super_class = None
+			for clas in c.class_diagram.classes:
+				if clas.name == s:
+					super_class = clas
+			if super_class == None:
+				Logger.showWarning("Class <" + c.name + "> has undefined super class <" + s + ">.")
+			else:
+				c.super_class_objs[s] = super_class
+
+		# calculate list of abstract methods
+		c.abstract_method_names = getClassAbstractMethodNames(c)
+
+		# check if <super> tags exist for all inherited classes
+		for name,obj in c.super_class_objs.iteritems():
+			if obj:
+				if name not in c.constructors[0].super_class_parameters:
+					num_params = len(obj.constructors[0].parameters)
+					if num_params > 0:
+						raise CompilerException("Class <" + c.name + "> inherits <" + name + "> and <" + name + ">'s constructor has " + str(num_params) + " parameter(s), but there's no <super> entry for that class in <" + c.name + ">'s constructor.")
+
+def getClassAbstractMethodNames(c):
+	abstract_method_names = []
+	non_abstract_method_names = []
+	for m in c.methods:
+		if m.isAbstract():
+			abstract_method_names.append(m.name)
+		else:
+			non_abstract_method_names.append(m.name)
+	for s in c.super_classes:
+		if s in c.super_class_objs:
+			super_abstract_method_names = getClassAbstractMethodNames(c.super_class_objs[s])
+			for m_name in super_abstract_method_names:
+				if m_name not in non_abstract_method_names:
+					abstract_method_names.append(m_name)
+	return abstract_method_names
+

+ 118 - 0
hybrid_server/python_sccd_compiler/utils.py

@@ -0,0 +1,118 @@
+from compiler_exceptions import CodeBlockException
+from sys import stdout
+
+class Logger(object):
+	verbose = 0 #-1= no output
+				#0 = only errors
+				#1 = only warnings and errors
+				#2 = all output
+				
+	@staticmethod   
+	def showError(error):
+		if(Logger.verbose > -1) :
+			print "ERROR : " + error
+				
+	@staticmethod
+	def showWarning(warning):
+		if(Logger.verbose > 0) :
+			print "WARNING : " + warning
+			
+	@staticmethod	
+	def showInfo(info):
+		if(Logger.verbose > 1) :
+			print "INFO : " + info
+
+#######################
+
+class Enum():	
+	def __init__(self, *entries):
+		self._keys = entries
+		self._map = {}
+		for v,k in enumerate(self._keys) :
+			self._map[k] = v
+			
+	def __getattr__(self, name):
+		return self._map[name]
+			
+	def name_of(self, index):
+		return self._keys[index]
+
+#######################
+
+NOT_SET = 0
+SPACES_USED = 1
+TABS_USED = 2
+
+class FormattedWriter:
+
+	def __init__(self, out = stdout):
+		self.out = out
+		self.indentLevel = 0
+		self.indentSpace = "\t"
+		self.first_write = True
+
+	def write(self, text = ""):
+		if self.first_write :
+			self.first_write = False
+			if text == "":
+				self.out.write(self.indentLevel*self.indentSpace)
+			else:
+				self.out.write(self.indentLevel*self.indentSpace + text)  
+		else:
+			if text == "":
+				self.out.write("\n" + self.indentLevel*self.indentSpace)
+			else:
+				self.out.write("\n" + self.indentLevel*self.indentSpace + text)
+	
+	def extendWrite(self, text = ""):
+		self.out.write(text)
+				
+	def indent(self):
+		self.indentLevel+=1
+
+	def dedent(self):
+		self.indentLevel-=1
+
+	def writeCodeCorrectIndent(self, body):
+		lines = body.split('\n')
+		while( len(lines) > 0 and lines[-1].strip() == "") :
+			del(lines[-1])
+	
+		index = 0;
+		while( len(lines) > index and lines[index].strip() == "") :	   
+			index += 1
+			
+		if index >= len(lines) :
+			return
+		#first index where valid code is present
+		to_strip_index = len(lines[index].rstrip()) - len(lines[index].strip()) 
+		indent_type = NOT_SET;
+			
+		while index < len(lines):
+			strip_part = lines[index][:to_strip_index]
+			
+			if( ('\t' in strip_part and ' ' in strip_part) or
+				(indent_type == SPACES_USED and '\t' in strip_part) or
+				(indent_type == TABS_USED and ' ' in strip_part)
+			) :
+				raise CodeBlockException("Mixed tab and space indentation!")
+			
+			if indent_type == NOT_SET :
+				if ' ' in strip_part :
+					indent_type = SPACES_USED
+				elif '\t' in strip_part :
+					indent_type = TABS_USED
+					
+			self.write(lines[index][to_strip_index:])
+			index += 1
+
+
+class FileWriter(FormattedWriter):
+
+	def __init__(self, filename):
+		FormattedWriter.__init__(self, open(filename, 'w'))
+
+	def close(self):
+		self.out.close()
+
+#######################

+ 30 - 0
hybrid_server/python_sccd_compiler/visitor.py

@@ -0,0 +1,30 @@
+class Visitor(object):
+	def _visit(self, node, prepend, *args):
+		prepend = prepend + "_"
+		meth = None
+		for cls in node.__class__.__mro__:
+			meth_name = prepend + cls.__name__
+			meth = getattr(self, meth_name, None)
+			if meth:
+				break
+
+		if not meth:
+			meth = self.generic_visit
+		return meth(node, *args)
+	
+	def visit(self, node, *args):
+		self._visit(node, "visit", *args)
+	
+	def enter(self, node, *args):
+		self._visit(node, "enter", *args)
+		
+	def exit(self, node, *args):
+		self._visit(node, "exit", *args)
+
+	def generic_visit(self, node):
+		#print 'generic_visit '+node.__class__.__name__
+		pass
+		
+class Visitable(object):
+	def accept(self, visitor):
+		visitor.visit(self) 

+ 4 - 0
hybrid_server/run.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+set -e
+./compile.sh
+python run_mvk_server.py

+ 19 - 0
hybrid_server/run_mvk_server.py

@@ -0,0 +1,19 @@
+import sys
+sys.path.append("../")
+
+import server
+import socket2event
+
+#import yappi
+#yappi.start()
+controller = server.Controller(sys.argv[1:])
+socket2event.boot_translation_service(controller)
+controller.start()
+
+try:
+    import time
+    while 1:
+        time.sleep(1)
+finally:
+    controller.stop()
+    #yappi.get_func_stats().sort("tsub").print_all()

Plik diff jest za duży
+ 1379 - 0
hybrid_server/server.py


+ 27 - 0
hybrid_server/server.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram author="Yentl Van Tendeloo" name="MvK Server">
+    <description>
+        Modelverse Kernel server. Server for the MvI, client of the MvS.
+    </description>
+    <top>
+        import time
+        import os
+        import urllib
+        import sys
+        import json
+
+        import sys
+        from collections import defaultdict
+        sys.path.append("../kernel/")
+        sys.path.append("../state/")
+        from modelverse_kernel.main import ModelverseKernel
+        from modelverse_state.main import ModelverseState
+    </top>
+
+    <inport name="socket_in"/>
+    <outport name="socket_out"/>
+
+    <class src="classes/mvkcontroller.xml" default="true"/>
+    <class src="classes/server.xml"/>
+    <class src="classes/socket.xml"/>
+</diagram>

+ 117 - 0
hybrid_server/socket2event.py

@@ -0,0 +1,117 @@
+import threading
+from python_runtime.statecharts_core import Event
+import socket
+
+send_data_queues = {}
+send_events = {}
+recv_events = {}
+run_sockets = {}
+
+def start_socket_threads(controller, sock):
+    recv_events[sock] = recv_event = threading.Event()
+    send_events[sock] = send_event = threading.Event()
+    send_data_queues[sock] = send_data_queue = []
+    run_sockets[sock] = True
+
+    thrd = threading.Thread(target=receive_from_socket, args=[controller, sock, recv_event])
+    thrd.daemon = True
+    thrd.start()
+
+    thrd = threading.Thread(target=send_to_socket, args=[controller, sock, send_data_queue, send_event])
+    thrd.daemon = True
+    thrd.start()
+
+def receive_from_socket(controller, sock, recv_event):
+    while 1:
+        recv_event.wait()
+        recv_event.clear()
+        if not run_sockets[sock]:
+            break
+        data = sock.recv(2**16)
+        controller.addInput(Event("received_socket", "socket_in", [sock, data]))
+
+def send_to_socket(controller, sock, data_queue, send_event):
+    while run_sockets[sock]:
+        send_event.wait()
+        send_event.clear()
+        while data_queue:
+            send = sock.send(data_queue.pop(0))
+            controller.addInput(Event("sent_socket", "socket_in", [sock, send]))
+        if not run_sockets[sock]:
+            break
+
+def _accept(controller, sock):
+    conn, addr = sock.accept()
+    start_socket_threads(controller, conn)
+    controller.addInput(Event("accepted_socket", "socket_in", [sock, conn]))
+
+def _connect(controller, sock, destination):
+    sock.connect(destination)
+    controller.addInput(Event("connected_socket", "socket_in", [sock]))
+
+def _close(controller, sock):
+    run_sockets[sock] = False
+    send_events[sock].set()
+    recv_events[sock].set()
+    sock.close()
+    controller.addInput(Event("closed_socket", "socket_in", [sock]))
+
+def _bind(controller, sock, addr):
+    sock.bind(addr)
+    controller.addInput(Event("bound_socket", "socket_in", [sock]))
+
+def _listen(controller, sock):
+    sock.listen(1)
+    controller.addInput(Event("listened_socket", "socket_in", [sock]))
+
+def _wrapper_func(*args):
+    func = args[0]
+    controller = args[1]
+    sock = args[2]
+    try:
+        func(*args[1:])
+    except socket.error as e:
+        print("ERROR " + str(e))
+        controller.addInput(Event("error_socket", "socket_in", [sock, e]))
+    except Exception as e:
+        print("UNKNOWN ERROR " + str(e))
+        controller.addInput(Event("unknown_error_socket", "socket_in", [sock, e]))
+
+def _start_on_daemon_thread(func, args):
+    new_args = [func]
+    new_args.extend(args)
+    args = new_args
+    thrd = threading.Thread(target=_wrapper_func, args=args)
+    thrd.daemon = True
+    thrd.start()
+
+def boot_translation_service(controller):
+    _start_on_daemon_thread(_poll, [controller, None])
+
+def _poll(controller, _):
+    socket_out = controller.addOutputListener("socket_out")
+    while 1:
+        evt = socket_out.fetch(-1)
+        name, params = evt.getName(), evt.getParameters()
+        if name == "accept_socket":
+            _start_on_daemon_thread(_accept, [controller, params[0]])
+        elif name == "recv_socket":
+            recv_events[params[0]].set()
+        elif name == "connect_socket":
+            _start_on_daemon_thread(_connect, [controller, params[0], params[1]])
+        elif name == "create_socket":
+            sock = socket.socket()
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            start_socket_threads(controller, sock)
+            controller.addInput(Event("created_socket", "socket_in", [sock]))
+        elif name == "close_socket":
+            _start_on_daemon_thread(_close, [controller, params[0]])
+        elif name == "send_socket":
+            send_data_queues[params[0]].append(params[1])
+            send_events[params[0]].set()
+        elif name == "bind_socket":
+            _start_on_daemon_thread(_bind, [controller, params[0], params[1]])
+        elif name == "listen_socket":
+            _start_on_daemon_thread(_listen, [controller, params[0]])
+        elif name == "stop":
+            break

+ 151 - 0
integration/code/b2dc.txt

@@ -0,0 +1,151 @@
+'"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'

+ 23 - 0
integration/code/binary_to_decimal.alc

@@ -0,0 +1,23 @@
+include "primitives.alh"
+
+Integer function b2d(param : String):
+	Integer value
+	value = 0
+	Integer length
+	length = string_len(param)
+	Integer counter
+	counter = integer_subtraction(length, 1)
+	Integer accumul
+	accumul = 1
+
+	while (integer_gte(counter, 0)):
+		if (string_eq(string_get(param, counter), "1")):
+			value = integer_addition(value, accumul)
+		accumul = integer_multiplication(accumul, 2)
+		counter = integer_subtraction(counter, 1)
+
+	return value
+
+Void function main():
+	while(True):
+		output(b2d(input()))

+ 11 - 0
integration/code/factorial.alc

@@ -0,0 +1,11 @@
+include "primitives.alh"
+
+Integer function factorial(n : Integer):
+	if(integer_lte(n, 1)):
+		return 1
+	else:
+		return integer_multiplication(n, factorial(integer_subtraction(n, 1)))
+
+Void function main():
+	while(True):
+		output(factorial(input()))

+ 11 - 0
integration/code/fibonacci.alc

@@ -0,0 +1,11 @@
+include "primitives.alh"
+
+Integer function fib(param : Integer):
+	if (integer_lte(param, 2)):
+		return 1
+	else:
+		return integer_addition(fib(integer_subtraction(param, 1)), fib(integer_subtraction(param, 2)))
+
+Void function main():
+	while(True):
+		output(fib(input()))

+ 17 - 0
integration/code/fibonacci_smart.alc

@@ -0,0 +1,17 @@
+include "primitives.alh"
+
+Element numbers = ?
+
+Integer function fib(param : Integer):
+	Integer new
+	while (integer_gt(param, list_len(numbers))):
+		new = list_len(numbers)
+		list_append(numbers, integer_addition(dict_read(numbers, integer_subtraction(new, 2)), dict_read(numbers, integer_subtraction(new, 1))))
+	return dict_read(numbers, integer_subtraction(param, 1))
+
+Void function main():
+	numbers = create_node()
+	list_append(numbers, 1)
+	list_append(numbers, 1)
+	while(True):
+		output(fib(input()))

+ 12 - 0
integration/code/if_elif.alc

@@ -0,0 +1,12 @@
+include "primitives.alh"
+
+Integer function compare_with_zero(n : Integer):
+	if(integer_lt(n, 0)):
+		return -1
+	elif(integer_eq(n, 0)):
+		return 0
+	return 1
+
+Void function main():
+	while(True):
+		output(compare_with_zero(input()))

+ 13 - 0
integration/code/if_elif_else.alc

@@ -0,0 +1,13 @@
+include "primitives.alh"
+
+Integer function compare_with_zero(n : Integer):
+	if(integer_lt(n, 0)):
+		return -1
+	elif(integer_eq(n, 0)):
+		return 0
+	else:
+		return 1
+
+Void function main():
+	while(True):
+		output(compare_with_zero(input()))

+ 27 - 0
integration/code/import_metamodel.alc

@@ -0,0 +1,27 @@
+Element function import_metamodel():
+	// TODO
+	//   For the moment, we make the assumption that it doesn't exist yet.
+	//   We create both the Simple Class Diagrams model, retype it, and then make the metamodel as an instance of this
+	//   In the future, this should already exist though...
+
+	// Instatiate as bottom
+	Element scd
+	Element scd_model
+	scd = create_node()
+	scd_model = create_node()
+	dict_add(scd, "model", scd_model)
+	instantiate_bottom_node(scd, "Class")
+	instantiate_bottom_value(scd, "__Type", Type)
+	instantiate_bottom_value(scd, "__String", String)
+	instantiate_bottom_edge(scd, "__Attribute_", dict_read(scd_model, "Class"), dict_read(scd_model, "__Type"))
+	instantiate_bottom_edge(scd, "__AttributeAttrs", dict_read(scd_model, "__Attribute_"), dict_read(scd_model, "__Type"))
+	instantiate_bottom_edge(scd, "__Attribute", dict_read(scd_model, "Class"), dict_read(scd_model, "__Type"))
+	instantiate_bottom_edge(scd, "__Name", dict_read(scd_model, "__Attribute"), dict_read(scd_model, "__String"))
+	instantiate_bottom_edge(scd, "Association", dict_read(scd_model, "Class"), dict_read(scd_model, "Class"))
+	instantiate_bottom_edge(scd, "Inheritance", dict_read(scd_model, "Class"), dict_read(scd_model, "Class"))
+	instantiate_bottom_edge(scd, "__inh_1", dict_read(scd_model, "Association"), dict_read(scd_model, "Class"))
+	instantiate_bottom_edge(scd, "__inh_2", dict_read(scd_model, "__Attribute_"), dict_read(scd_model, "Class"))
+
+	// Instantiated, now retype to make sure that everything is correct
+	Element mapping
+	mapping = create_node()

+ 326 - 0
integration/code/import_metamodel_cs.txt

@@ -0,0 +1,326 @@
+'"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'

+ 16 - 0
integration/code/leap_year.alc

@@ -0,0 +1,16 @@
+include "lib_remainder.alc"
+
+Boolean function leap_year(year : Integer):
+	// Is a leap year if it is divisible by 4
+	if (integer_eq(remainder(year, 4), 0)):
+		// Unless it is also divisible by 1000
+		if (integer_eq(remainder(year, 1000), 0)):
+			return False
+		else:
+			return True
+	else:
+		return False
+
+Void function main():
+	while (True):
+		output(leap_year(input()))

+ 4 - 0
integration/code/lib_remainder.alc

@@ -0,0 +1,4 @@
+include "primitives.alh"
+
+Integer function remainder(a : Integer, b: Integer):
+	return integer_subtraction(a, integer_multiplication(integer_division(a, b), b))

+ 6 - 0
integration/code/main.alc

@@ -0,0 +1,6 @@
+include "io.alh"
+
+Void function main():
+	while(True):
+		output("Hello, world!")
+	return

+ 556 - 0
integration/code/pn_interface.alc

@@ -0,0 +1,556 @@
+include "primitives.alh"
+include "constructors.alh"
+include "object_operations.alh"
+include "library.alh"
+include "conformance_scd.alh"
+include "io.alh"
+
+Element function create_metamodels():
+	// TODO
+	//   For the moment, we make the assumption that it doesn't exist yet.
+	//   We create both the Simple Class Diagrams model, retype it, and then make the metamodel as an instance of this
+	//   In the future, this should already exist though...
+
+	if (bool_not(dict_in(dict_read(read_root(), "__hierarchy"), "models"))):
+		Element scd
+		Element scd_model
+		scd = create_node()
+		scd_model = create_node()
+		dict_add(scd, "model", scd_model)
+		instantiate_bottom_node(scd, "Class")
+		instantiate_bottom_value(scd, "Type", Type)
+		instantiate_bottom_value(scd, "__String", String)
+		instantiate_bottom_value(scd, "__name", "name")
+		instantiate_bottom_edge(scd, "Attribute", dict_read(scd_model, "Class"), dict_read(scd_model, "Type"))
+		instantiate_bottom_edge(scd, "__Name", dict_read(scd_model, "Attribute"), dict_read(scd_model, "__String"))
+		instantiate_bottom_edge(scd, "Association", dict_read(scd_model, "Class"), dict_read(scd_model, "Class"))
+		instantiate_bottom_edge(scd, "Inheritance", dict_read(scd_model, "Class"), dict_read(scd_model, "Class"))
+		instantiate_bottom_edge(scd, "__name_edge", dict_read(scd_model, "__Name"), dict_read(scd_model, "__name"))
+		instantiate_bottom_edge(scd, "__inh_1", dict_read(scd_model, "Association"), dict_read(scd_model, "Class"))
+		instantiate_bottom_edge(scd, "__inh_2", dict_read(scd_model, "Attribute"), dict_read(scd_model, "Class"))
+		instantiate_bottom_value(scd, "__attribute", "attribute")
+		instantiate_bottom_edge(scd, "__attribute_edge", dict_read(scd_model, "Attribute"), dict_read(scd_model, "__attribute"))
+
+		// Instantiated, now retype to make sure that everything is correct
+		Element mapping
+		mapping = create_node()
+		dict_add(mapping, dict_read(scd_model, "Class"), dict_read(scd_model, "Class"))
+		dict_add(mapping, dict_read(scd_model, "Type"), dict_read(scd_model, "Type"))
+		dict_add(mapping, dict_read(scd_model, "__String"), dict_read(scd_model, "Type"))
+		dict_add(mapping, dict_read(scd_model, "Attribute"), dict_read(scd_model, "Attribute"))
+		dict_add(mapping, dict_read(scd_model, "__Name"), dict_read(scd_model, "Attribute"))
+		dict_add(mapping, dict_read(scd_model, "Association"), dict_read(scd_model, "Association"))
+		dict_add(mapping, dict_read(scd_model, "Inheritance"), dict_read(scd_model, "Association"))
+		dict_add(mapping, dict_read(scd_model, "__inh_1"), dict_read(scd_model, "Inheritance"))
+		dict_add(mapping, dict_read(scd_model, "__inh_2"), dict_read(scd_model, "Inheritance"))
+		dict_add(mapping, dict_read(scd_model, "__name"), dict_read(scd_model, "__String"))
+		dict_add(mapping, dict_read(scd_model, "__name_edge"), dict_read(scd_model, "__Name"))
+		dict_add(mapping, dict_read(scd_model, "__attribute"), dict_read(scd_model, "__String"))
+		dict_add(mapping, dict_read(scd_model, "__attribute_edge"), dict_read(scd_model, "__Name"))
+		retype(scd, scd, dict_read(scd_model, "Inheritance"), mapping)
+		export_node("models/SimpleClassDiagrams", scd)
+
+		// TODO this code is also very dirty as there is no nice "dictionary" and "list" syntax yet
+		Element pn_metamodel
+		pn_metamodel = instantiate_new_model(scd, dict_read(scd_model, "Inheritance"))
+		Element tokens
+		tokens = create_node()
+		dict_add(tokens, "tokens", Integer)
+		instantiate_model_lib(pn_metamodel, dict_read(scd_model, "Class"), "Place", create_node(), tokens, create_node())
+		instantiate_model_lib(pn_metamodel, dict_read(scd_model, "Class"), "Transition", create_node(), create_node(), create_node())
+		Element weight
+		weight = create_node()
+		dict_add(weight, "weight", Integer)
+		Element p2t_links
+		p2t_links = create_node()
+		list_append(p2t_links, dict_read(dict_read(pn_metamodel, "model"), "Place"))
+		list_append(p2t_links, dict_read(dict_read(pn_metamodel, "model"), "Transition"))
+		Element t2p_links
+		t2p_links = create_node()
+		list_append(t2p_links, dict_read(dict_read(pn_metamodel, "model"), "Transition"))
+		list_append(t2p_links, dict_read(dict_read(pn_metamodel, "model"), "Place"))
+		instantiate_model_lib(pn_metamodel, dict_read(scd_model, "Association"), "P2T", p2t_links, weight, create_node())
+		instantiate_model_lib(pn_metamodel, dict_read(scd_model, "Association"), "T2P", t2p_links, weight, create_node())
+
+		set_model_constraints(pn_metamodel, petrinet_constraints)
+		export_node("models/PetriNets", pn_metamodel)
+
+		// Also create conformance bottom metamodel
+		Element mm_bottom
+		Element mm_bottom_model
+		mm_bottom = create_node()
+		mm_bottom_model = create_node()
+		dict_add(mm_bottom, "model", mm_bottom_model)
+		instantiate_bottom_node(mm_bottom, "Node")
+		instantiate_bottom_value(mm_bottom, "Type", Type)
+		instantiate_bottom_value(mm_bottom, "Integer", Integer)
+		instantiate_bottom_value(mm_bottom, "Action", Action)
+		instantiate_bottom_value(mm_bottom, "Float", Float)
+		instantiate_bottom_value(mm_bottom, "String", String)
+		instantiate_bottom_value(mm_bottom, "Boolean", Boolean)
+		instantiate_bottom_edge(mm_bottom, "Edge", dict_read(mm_bottom_model, "Node"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__Inheritance", dict_read(mm_bottom_model, "Node"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_1", dict_read(mm_bottom_model, "Type"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_2", dict_read(mm_bottom_model, "Integer"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_3", dict_read(mm_bottom_model, "Action"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_4", dict_read(mm_bottom_model, "Float"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_5", dict_read(mm_bottom_model, "String"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_6", dict_read(mm_bottom_model, "Boolean"), dict_read(mm_bottom_model, "Node"))
+		instantiate_bottom_edge(mm_bottom, "__inh_7", dict_read(mm_bottom_model, "Edge"), dict_read(mm_bottom_model, "Node"))
+
+		// Retype it with itself
+		mapping = create_node()
+		dict_add(mapping, dict_read(mm_bottom_model, "Node"), dict_read(mm_bottom_model, "Node"))
+		dict_add(mapping, dict_read(mm_bottom_model, "Type"), dict_read(mm_bottom_model, "Type"))
+		dict_add(mapping, dict_read(mm_bottom_model, "Integer"), dict_read(mm_bottom_model, "Type"))
+		dict_add(mapping, dict_read(mm_bottom_model, "Float"), dict_read(mm_bottom_model, "Type"))
+		dict_add(mapping, dict_read(mm_bottom_model, "String"), dict_read(mm_bottom_model, "Type"))
+		dict_add(mapping, dict_read(mm_bottom_model, "Boolean"), dict_read(mm_bottom_model, "Type"))
+		dict_add(mapping, dict_read(mm_bottom_model, "Action"), dict_read(mm_bottom_model, "Type"))
+		dict_add(mapping, dict_read(mm_bottom_model, "Edge"), dict_read(mm_bottom_model, "Edge"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__Inheritance"), dict_read(mm_bottom_model, "Edge"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_1"), dict_read(mm_bottom_model, "__Inheritance"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_2"), dict_read(mm_bottom_model, "__Inheritance"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_3"), dict_read(mm_bottom_model, "__Inheritance"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_4"), dict_read(mm_bottom_model, "__Inheritance"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_5"), dict_read(mm_bottom_model, "__Inheritance"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_6"), dict_read(mm_bottom_model, "__Inheritance"))
+		dict_add(mapping, dict_read(mm_bottom_model, "__inh_7"), dict_read(mm_bottom_model, "__Inheritance"))
+		retype(mm_bottom, mm_bottom, dict_read(mm_bottom_model, "__Inheritance"), mapping)
+		export_node("models/LTM_bottom", mm_bottom)
+
+	return 0
+
+String function petrinet_constraints(pn_mo : Element):
+	// Check places to have positive number of tokens
+	Element all_elems
+	Element elem_constraint
+	all_elems = allInstances(pn_mo, dict_read(dict_read(dict_read(pn_mo, "metamodel"), "model"), "Place"))
+	while (integer_lt(0, read_nr_out(all_elems))):
+		elem_constraint = set_pop(all_elems)
+		if (integer_lt(readAttribute(pn_mo, elem_constraint, "tokens"), 0)):
+			return string_join("Negative number of tokens in Place ", getName(pn_mo, elem_constraint))
+
+	// Check P2T transitions to have positive weight
+	all_elems = allInstances(pn_mo, dict_read(dict_read(dict_read(pn_mo, "metamodel"), "model"), "P2T"))
+	while (integer_lt(0, read_nr_out(all_elems))):
+		elem_constraint = set_pop(all_elems)
+		if (integer_lt(readAttribute(pn_mo, elem_constraint, "weight"), 0)):
+			return string_join("Negative weight in arc ", getName(pn_mo, elem_constraint))
+
+	// Check T2P transitions to have positive weight
+	all_elems = allInstances(pn_mo, dict_read(dict_read(dict_read(pn_mo, "metamodel"), "model"), "T2P"))
+	while (integer_lt(0, read_nr_out(all_elems))):
+		elem_constraint = set_pop(all_elems)
+		if (integer_lt(readAttribute(pn_mo, elem_constraint, "weight"), 0)):
+			return string_join("Negative weight in arc ", getName(pn_mo, elem_constraint))
+
+	return "OK"
+
+Element function pn_operations():
+	Element ops
+	ops = create_node()
+	dict_add(ops, "fire", petrinet_fire)
+	dict_add(ops, "enabled", petrinet_enabled)
+	return ops
+
+Element function petrinet_enabled(pn_m : Element):
+	Element set_enabled
+	set_enabled = petrinet_enabled_set(pn_m)
+	output("Enabled transitions:")
+	while (integer_lt(0, read_nr_out(set_enabled))):
+		output(getName(pn_m, set_pop(set_enabled)))
+	return pn_m
+
+Element function petrinet_enabled_set(pn_mod : Element):
+	Element all_transitions
+	all_transitions = allInstances(pn_mod, dict_read(dict_read(dict_read(pn_mod, "metamodel"), "model"), "Transition"))
+
+	Element enabled_transitions
+	enabled_transitions = create_node()
+
+	Element under_study
+	Element in_arcs
+	Element arc_under_study
+	Boolean enabled
+	while (integer_lt(0, read_nr_out(all_transitions))):
+		under_study = set_pop(all_transitions)
+		enabled = True
+
+		// Find all incoming transitions
+		in_arcs = allIncomingAssociationInstances(pn_mod, under_study, dict_read(dict_read(dict_read(pn_mod, "metamodel"), "model"), "P2T"))
+
+		while (integer_lt(0, read_nr_out(in_arcs))):
+			arc_under_study = set_pop(in_arcs)
+
+			Integer present_tokens
+			Integer required_tokens
+			required_tokens = readAttribute(pn_mod, arc_under_study, "weight")
+			present_tokens = readAttribute(pn_mod, read_edge_src(arc_under_study), "tokens")
+			if (integer_lt(present_tokens, required_tokens)):
+				// Less tokens than required, so disable the transition completely
+				enabled = False
+
+		if (enabled):
+			set_add(enabled_transitions, under_study)
+
+	return enabled_transitions
+
+Element function petrinet_fire(pn_mode : Element):
+	output("Transition to fire?")
+	Element transition
+	transition = input()
+	if (dict_in(dict_read(pn_mode, "model"), transition)):
+		transition = dict_read(dict_read(pn_mode, "model"), transition)
+		if (set_in(petrinet_enabled_set(pn_mode), transition)):
+			Element workset
+			Element working_place
+			Element working_arc
+
+			// Consume tokens
+			workset = allIncomingAssociationInstances(pn_mode, transition, dict_read(dict_read(dict_read(pn_mode, "metamodel"), "model"), "P2T"))
+			while (integer_lt(0, read_nr_out(workset))):
+				working_arc = set_pop(workset)
+				working_place = read_edge_src(working_arc)
+				setAttribute(pn_mode, working_place, "tokens", integer_subtraction(readAttribute(pn_mode, working_place, "tokens"), readAttribute(pn_mode, working_arc, "weight")))
+				output(string_join(string_join(string_join("  ", getName(pn_mode, working_place)), ": "), cast_i2s(readAttribute(pn_mode, working_place, "tokens"))))
+
+			// Add tokens
+			workset = allOutgoingAssociationInstances(pn_mode, transition, dict_read(dict_read(dict_read(pn_mode, "metamodel"), "model"), "T2P"))
+			while (integer_lt(0, read_nr_out(workset))):
+				working_arc = set_pop(workset)
+				working_place = read_edge_dst(working_arc)
+				setAttribute(pn_mode, working_place, "tokens", integer_addition(readAttribute(pn_mode, working_place, "tokens"), readAttribute(pn_mode, working_arc, "weight")))
+				output(string_join(string_join(string_join("  ", getName(pn_mode, working_place)), ": "), cast_i2s(readAttribute(pn_mode, working_place, "tokens"))))
+			output("Transition fired!")
+		else:
+			output("Cannot fire if not enabled; aborting")
+	else:
+		output("Unknown transition; aborting")
+	return pn_mode
+	
+Element function petrinet_loaded(pn_model : Element):
+	String cmd
+
+	Element attr_list_pn
+	Element attr_keys_pn
+	Element attr_key_pn
+	Element metamodel_element_pn
+	String typename
+	Boolean bottom
+	Element other_metamodel
+
+	bottom = False
+	other_metamodel = create_node()
+	dict_add(other_metamodel, "model", dict_read(pn_model, "model"))
+	dict_add(other_metamodel, "type_mapping", create_node())
+	dict_add(other_metamodel, "metamodel", import_node("models/LTM_bottom"))
+	dict_add(other_metamodel, "inheritance", dict_read(dict_read(dict_read(other_metamodel, "metamodel"), "model"), "__Inheritance"))
+
+	output("Model loaded, ready for commands!")
+	output("Use 'help' command for a list of possible commands")
+
+	while (True):
+		output("Please give your command.")
+		cmd = input()
+		if (string_eq(cmd, "help")):
+			output("Generic model operations:")
+			output("  instantiate -- Create a new model element")
+			output("  delete      -- Delete an existing element")
+			output("  modify      -- Modify attribute of an existing element")
+			output("  rename      -- Rename an existing element")
+			output("  list        -- Prints the list of elements in the model")
+			output("  types       -- Prints the list of elements that can be instantiated")
+			output("  read        -- Prints the current state of a model element")
+			output("  verify      -- Check whether the model conforms to the metamodel")
+			output("  retype      -- Change the type of an element")
+			output("  switch      -- Switch between conformance bottom and the linguistic metamodel")
+			output("  exit        -- Unload the model and go back to the loading prompt")
+			if (bool_not(bottom)):
+				output("Model-specific operations:")
+				Element specific_ops
+				specific_ops = dict_keys(pn_operations())
+				while (integer_lt(0, dict_len(specific_ops))):
+					output(string_join("  ", set_pop(specific_ops)))
+		elif (string_eq(cmd, "exit")):
+			return pn_model
+		elif (string_eq(cmd, "instantiate")):
+			String mm_type_name
+			output("Type to instantiate?")
+			mm_type_name = input()
+			if (dict_in(dict_read(dict_read(pn_model, "metamodel"), "model"), mm_type_name)):
+				metamodel_element_pn = dict_read(dict_read(dict_read(pn_model, "metamodel"), "model"), mm_type_name)
+				String element_name
+				output("Name of new element?")
+				element_name = input()
+				if (dict_in(dict_read(pn_model, "model"), element_name)):
+					output("Element already exists; aborting")
+				else:
+					Boolean cnt
+					cnt = True
+					Element additional_opts
+					additional_opts = create_node()
+					if (is_edge(metamodel_element_pn)):
+						output("Source name?")
+						String src_name
+						src_name = input()
+						if (dict_in(dict_read(pn_model, "model"), src_name)):
+							list_append(additional_opts, dict_read(dict_read(pn_model, "model"), src_name))
+							output("Destination name?")
+							String dst_name
+							dst_name = input()
+							if (dict_in(dict_read(pn_model, "model"), dst_name)):
+								list_append(additional_opts, dict_read(dict_read(pn_model, "model"), dst_name))
+							else:
+								output("Unknown destination; aborting")
+								cnt = False
+						else:
+							output("Unknown source; aborting")
+							cnt = False
+					if (type_eq(typeof(metamodel_element_pn), Type)):
+						// It is a value
+						output("Value?")
+						list_append(additional_opts, input())
+					if (cnt):
+						attr_list_pn = getAttributeList(pn_model, metamodel_element_pn)
+						attr_keys_pn = dict_keys(attr_list_pn)
+						Element attrs
+						attrs = create_node()
+						while (integer_lt(0, read_nr_out(attr_keys_pn))):
+							attr_key_pn = set_pop(attr_keys_pn)
+							output(string_join(string_join(string_join(attr_key_pn, " : "), cast_t2s(dict_read(attr_list_pn, attr_key_pn))), "?"))
+							dict_add(attrs, attr_key_pn, input())
+						Element resulting_element
+						resulting_element = instantiate_model_lib(pn_model, metamodel_element_pn, element_name, additional_opts, create_node(), attrs)
+						output("Instantiation successful!")
+			else:
+				output("Unknown type specified; aborting")
+		elif (string_eq(cmd, "delete")):
+			output("What is the name of the element you want to delete?")
+			cmd = input()
+			if (dict_in(dict_read(pn_model, "model"), cmd)):
+				delete_element(dict_read(dict_read(pn_model, "model"), cmd))
+				output("Deleted!")
+			else:
+				output("No such element; aborting")
+		elif (string_eq(cmd, "modify")):
+			output("Element to modify?")
+			cmd = input()
+			if (dict_in(dict_read(pn_model, "model"), cmd)):
+				Element mod
+				mod = dict_read(dict_read(pn_model, "model"), cmd)
+				metamodel_element_pn = dict_read_node(dict_read(pn_model, "type_mapping"), mod)
+
+				attr_list_pn = getAttributeList(pn_model, metamodel_element_pn)
+				attr_keys_pn = dict_keys(attr_list_pn)
+				while (integer_lt(0, read_nr_out(attr_keys_pn))):
+					attr_key_pn = set_pop(attr_keys_pn)
+					output(string_join(string_join(string_join("   ", attr_key_pn), " : "), cast_t2s(dict_read(attr_list_pn, attr_key_pn))))
+
+				output("Attribute to modify?")
+				String attr_name
+				attr_name = input()
+				if (set_in(dict_keys(getAttributeList(pn_model, metamodel_element_pn)), attr_name)):
+					output("New value?")
+					setAttribute(pn_model, mod, attr_name, input())
+					output("Modified!")
+				else:
+					output("Unknown attribute; aborting")
+			else:
+				output("Element does not exist; aborting")
+		elif (string_eq(cmd, "rename")):
+			output("Old name?")
+			String old_name_e
+			old_name_e = input()
+			if (dict_in(dict_read(pn_model, "model"), old_name_e)):
+				output("New name?")
+				String new_name_e
+				new_name_e = input()
+				if (dict_in(dict_read(pn_model, "model"), new_name_e)):
+					output("New name already used; aborting")
+				else:
+					dict_add(dict_read(pn_model, "model"), new_name_e, dict_read(dict_read(pn_model, "model"), old_name_e))
+					dict_delete(dict_read(pn_model, "model"), old_name_e)
+					output("Rename complete!")
+			else:
+				output("Unknown element; aborting")
+		elif (string_eq(cmd, "list")):
+			Element keys_m
+			keys_m = dict_keys(dict_read(pn_model, "model"))
+			output("List of all elements:")
+			Element v_m
+			while (integer_gt(read_nr_out(keys_m), 0)):
+				v_m = set_pop(keys_m)
+				// Filter out anonymous objects
+				typename = getName(dict_read(pn_model, "metamodel"), dict_read_node(dict_read(pn_model, "type_mapping"), dict_read(dict_read(pn_model, "model"), v_m)))
+				if (bool_not(string_startswith(v_m, "__"))):
+					output(string_join(string_join(string_join("  ", v_m), " : "), typename))
+		elif (string_eq(cmd, "read")):
+			output("Element to read?")
+			cmd = input()
+			if (dict_in(dict_read(pn_model, "model"), cmd)):
+				Element read_elem
+				read_elem = dict_read(dict_read(pn_model, "model"), cmd)
+				metamodel_element_pn = dict_read_node(dict_read(pn_model, "type_mapping"), read_elem)
+
+				output(string_join("Name: ", cmd))
+				output(string_join("Type: ", getName(dict_read(pn_model, "metamodel"), metamodel_element_pn)))
+				if (is_edge(read_elem)):
+					output(string_join("Source: ", getName(pn_model, read_edge_src(read_elem))))
+					output(string_join("Destination: ", getName(pn_model, read_edge_dst(read_elem))))
+				if (string_neq(cast_v2s(read_elem), "None")):
+					output(string_join("Value: ", cast_v2s(read_elem)))
+				output("Defines attributes:")
+				attr_list_pn = getInstantiatableAttributes(pn_model, read_elem)
+				attr_keys_pn = dict_keys(attr_list_pn)
+				while (integer_lt(0, read_nr_out(attr_keys_pn))):
+					attr_key_pn = set_pop(attr_keys_pn)
+					output(string_join(string_join(string_join("   ", attr_key_pn), " : "), cast_t2s(dict_read(attr_list_pn, attr_key_pn))))
+				output("Attributes:")
+				attr_list_pn = getAttributeList(pn_model, metamodel_element_pn)
+				attr_keys_pn = dict_keys(attr_list_pn)
+				while (integer_lt(0, read_nr_out(attr_keys_pn))):
+					attr_key_pn = set_pop(attr_keys_pn)
+					output(string_join(string_join(string_join(string_join(string_join("   ", attr_key_pn), " : "), cast_t2s(dict_read(attr_list_pn, attr_key_pn))), " = "), cast_v2s(readAttribute(pn_model, read_elem, attr_key_pn))))
+			else:
+				output("Unknown element; aborting")
+		elif (string_eq(cmd, "verify")):
+			output(conformance_scd(pn_model))
+		elif (string_eq(cmd, "types")):
+			Element keys_t
+			keys_t = dict_keys(dict_read(dict_read(pn_model, "metamodel"), "model"))
+			output("List of types:")
+			Element v_t
+			while (integer_gt(read_nr_out(keys_t), 0)):
+				v_t = set_pop(keys_t)
+				if (bool_not(string_startswith(v_t, "__"))):
+					output(string_join(string_join(string_join("  ", v_t), " : "), getName(dict_read(dict_read(pn_model, "metamodel"), "metamodel"), dict_read_node(dict_read(dict_read(pn_model, "metamodel"), "type_mapping"), dict_read(dict_read(dict_read(pn_model, "metamodel"), "model"), v_t)))))
+		elif (string_eq(cmd, "retype")):
+			output("Element to retype?")
+			String elementname
+			elementname = input()
+			if (dict_in(dict_read(pn_model, "model"), elementname)):
+				output("New type")
+				typename = input()
+				if (dict_in(dict_read(dict_read(pn_model, "metamodel"), "model"), typename)):
+					// OK, do the retyping
+					// First try removing the previous type if it exists
+					dict_delete(dict_read(pn_model, "type_mapping"), dict_read(dict_read(pn_model, "model"), elementname))
+					// Now add the new type
+					dict_add(dict_read(pn_model, "type_mapping"), dict_read(dict_read(pn_model, "model"), elementname), dict_read(dict_read(dict_read(pn_model, "metamodel"), "model"), typename))
+					output("Retyped!")
+				else:
+					output("Unknown type; aborting")
+			else:
+				output("Unknown element; aborting")
+		elif (string_eq(cmd, "switch")):
+			bottom = bool_not(bottom)
+
+			Element tmp_model
+			tmp_model = pn_model
+			pn_model = other_metamodel
+			other_metamodel = tmp_model
+
+			if (bottom):
+				// The type mapping we are using is probably not complete for our model
+				// so we completely recreate it from the model we have.
+				output("Switching to conformance bottom mode!")
+				generate_bottom_type_mapping(pn_model)
+			else:
+				// We already switched the models and such, so we are already done!
+				output("Switching to linguistic metamodel!")
+		elif (bool_and(dict_in(pn_operations(), cmd), bool_not(bottom))):
+			// A model-specific operation, so execute that one
+			Element specific_op
+			specific_op = dict_read(pn_operations(), cmd)
+			specific_op(pn_model)
+		else:
+			output("Unknown command; aborting")
+			output("Use command 'help' to get a list of available commands")
+
+Element function initial_prompt():
+	output("Welcome to the Model Management Interface, running live on the Modelverse!")
+	output("Use 'help' command for a list of possible commands")
+	String command
+	Element root
+	Element metamodel
+	String name
+	Element my_model
+	String mm_name
+
+	create_metamodels()
+
+	dict_add(dict_read(read_root(), "__hierarchy"), "models", create_node())
+	root = dict_read(dict_read(read_root(), "__hierarchy"), "models")
+
+	while (True):
+		output("Please give your command.")
+		command = input()
+
+		if (string_eq(command, "help")):
+			output("Currently no model is loaded, so your operations are limited to:")
+			output("  new    -- Create a new model and save it for future use")
+			output("  load   -- Load a previously made model")
+			output("  rename -- Rename a previously made model")
+			output("  delete -- Delete a previously made model")
+			output("  list   -- Show a list of all stored models")
+			output("  help   -- Show a list of possible commands")
+		elif (string_eq(command, "new")):
+			output("Metamodel to instantiate?")
+			mm_name = input()
+			if (dict_in(root, mm_name)):
+				output("Name of model?")
+				name = input()
+				if (dict_in(root, name)):
+					output("Model exists; aborting")
+				else:
+					my_model = instantiate_new_model(dict_read(root, mm_name), create_node())
+					dict_add(root, name, my_model)
+					petrinet_loaded(my_model)
+			else:
+				output("Unknown metamodel; aborting")
+		elif (string_eq(command, "load")):
+			output("Model to load?")
+			name = input()
+			if (dict_in(root, name)):
+				my_model = dict_read(root, name)
+				petrinet_loaded(my_model)
+			else:
+				output("Model not found; aborting")
+		elif (string_eq(command, "list")):
+			Element keys
+			keys = dict_keys(root)
+			output("Found models:")
+			while (integer_gt(read_nr_out(keys), 0)):
+				Element m_menu_list
+				m_menu_list = set_pop(keys)
+				output(string_join(string_join(string_join("  ", m_menu_list), " : "), reverseNameLookup(root, dict_read(dict_read(root, m_menu_list), "metamodel"))))
+		elif (string_eq(command, "delete")):
+			output("Model to delete?")
+			name = input()
+			if (dict_in(root, name)):
+				dict_delete(root, name)
+				output("Deleted!")
+			else:
+				output("Model not found; aborting")
+		elif (string_eq(command, "rename")):
+			output("Old name?")
+			String old_name
+			old_name = input()
+			if (dict_in(root, old_name)):
+				output("New name?")
+				String new_name
+				new_name = input()
+				if (dict_in(root, new_name)):
+					output("Model exists; aborting")
+				else:
+					dict_add(root, new_name, dict_read(root, old_name))
+					dict_delete(root, old_name)
+					output("Rename complete!")
+			else:
+				output("Model not found; aborting")
+		else:
+			output("Command not recognized, use 'help' for a list of possible commands")
+
+Void function main():
+	initial_prompt()

+ 11 - 0
integration/code/power.alc

@@ -0,0 +1,11 @@
+include "primitives.alh"
+
+Integer function power(base : Integer, exponent : Integer):
+	if (integer_eq(exponent, 0)):
+		return 1
+	else:
+		return integer_multiplication(base, power(base, integer_subtraction(exponent, 1)))
+
+Void function main():
+	while (True):
+		output(power(input(), input()))

+ 5 - 0
integration/code/remainder.alc

@@ -0,0 +1,5 @@
+include "lib_remainder.alc"
+
+Void function main():
+	while(True):
+		output(remainder(input(), input()))

+ 21 - 0
integration/code/revert.alc

@@ -0,0 +1,21 @@
+include "primitives.alh"
+
+String function revert_string(a : String):
+	Integer length
+	length = string_len(a)
+
+	Integer counter
+	counter = 0
+
+	String result
+	result = ""
+
+	while (integer_lt(counter, length)):
+		result = string_join(string_get(a, counter), result)
+		counter = integer_addition(counter, 1)
+
+	return result
+
+Void function main():
+	while (True):
+		output(revert_string(input()))

+ 17 - 0
integration/test_binary2decimal.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestBinary2Decimal(unittest.TestCase):
+    def test_po_binary2decimal(self):
+        self.binary2decimal("PO")
+
+    def test_co_binary2decimal(self):
+        self.binary2decimal("CO")
+
+    def binary2decimal(self, mode):
+        self.assertTrue(run_file(["binary_to_decimal.alc", "primitives.alc"],
+            ["1", "10", "11", "100", "001", "1100111101"],
+            ["1", "2", "3", "4", "1", "829"],
+            mode))

+ 328 - 0
integration/test_constructors_al.py

@@ -0,0 +1,328 @@
+import unittest
+import sys
+import os
+
+from utils import execute, kill, run_file, run_barebone
+
+def flatten(lst):
+    new_lst = []
+    for f in lst:
+        if isinstance(f, (list, tuple)):
+            new_lst.extend(flatten(f))
+        else:
+            new_lst.append(f)
+    return new_lst
+
+class TestConstructorsActionLanguage(unittest.TestCase):
+    def test_constructors_simple(self):
+        commands = [('"output"',                    # Output
+                        ('"const"', 'true'),
+                        'true',                     # (has next)
+                        ('"return"',                # Return
+                            'true',                 # (has value)
+                            ('"const"', 'true'),
+                        ),
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["True"], 1))
+
+    def test_constructors_if_else_true(self):
+        commands = [('"if"',                    # If
+                        ('"const"', 'true'),    # Condition
+                        ('"output"',            # True-part
+                            ('"const"', 'true'),
+                            'false',            # Has next
+                        ),
+                        'true',                 # Has else
+                        ('"output"',            # False-part
+                            ('"const"', 'false'),
+                            'false',            # Has next
+                        ),
+                        'true',                 # Has next
+                        ('"return"',            # Return
+                            'true',             # Has value
+                            ('"const"', "true"),
+                        ),
+
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["True"], 1))
+
+    def test_constructors_if_else_false(self):
+        commands = [('"if"',                    # If
+                        ('"const"', 'false'),   # Condition
+                        ('"output"',            # True-part
+                            ('"const"', 'true'),
+                            'false',            # Has next
+                        ),
+                        'true',                 # Has else
+                        ('"output"',            # False-part
+                            ('"const"', 'false'),
+                            'false',            # Has next
+                        ),
+                        'true',                 # Has next
+                        ('"return"',            # Return
+                            'true',             # Has value
+                            ('"const"', "true"),
+                        ),
+
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["False"], 1))
+
+    def test_constructors_if_true(self):
+        commands = [('"if"',                    # If
+                        ('"const"', 'true'),    # Condition
+                        ('"output"',            # True-part
+                            ('"const"', 'true'),
+                            'false',            # Has next
+                        ),
+                        'false',                # Has else
+                        'true',                 # Has next
+                        ('"return"',            # Return
+                            'true',             # Has value
+                            ('"const"', "true"),
+                        ),
+
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["True"], 1))
+
+    def test_constructors_if_false(self):
+        commands = [('"if"',                    # If
+                        ('"const"', 'false'),   # Condition
+                        ('"output"',            # True-part
+                            ('"const"', 'true'),
+                            'false',            # Has next
+                        ),
+                        'false',                # Has else
+                        'true',                 # Has next
+                        ('"return"',            # Return
+                            'true',             # Has value
+                            ('"const"', "true"),
+                        ),
+
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), [None], 1, timeout=True))
+
+    def test_constructors_addition(self):
+        commands = [('"output"',
+                        ('"call"',
+                            ('"deref"', '"primitives/integer_addition"'),
+                            '2',
+                            ('"const"', '1'),
+                            ('"const"', '5'),
+                            'false',
+                        ),
+                        'true',
+                        ('"return"', 'true', '"const"', 'true'),
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["6"], 1))
+
+    def test_constructors_while_false(self):
+        commands = [('"while"',                 # While
+                        ('"const"', 'false'),   # Condition
+                        ('"output"',            # True-part
+                            ('"const"', 'true'),
+                            'false',            # Has next
+                        ),
+                        'true',                 # Has next
+                        ('"output"',            # Output false
+                            ('"const"', 'false'),
+                            'true',             # Has next
+                            ('"return"',        # Return
+                                'true',         # Has value
+                                ('"const"', "true"),
+                            ),
+                        ),
+
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["False"], 1))
+
+    def test_constructors_while_true(self):
+        commands = ['"while"',                 # While
+                        '"const"', 'true',    # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'true',                 # Has next
+                        '"output"',            # False-part
+                            '"const"', 'false',
+                            'true',            # Has next
+                        '"return"',            # Return
+                            'true',             # Has value
+                            '"const"', "true",
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["True", "True", "True", "True"], 1))
+
+    def test_constructors_declare_and_assign(self):
+        commands = ['"declare"',
+                        1,
+                        'true',
+                    '"assign"',
+                        '"resolve"', 1,
+                        '"const"', '5',
+                        'true',
+                    '"output"',
+                        '"access"', '"resolve"', 1,
+                        'true',
+                    '"return"',
+                        'true',
+                        '"const"', "true",
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["5"], 1))
+
+    def test_constructors_output_input(self):
+        commands = ['"output"',
+                        '"input"',
+                        'true',
+                    '"return"',
+                        'true',
+                        '"const"', "true",
+                ]
+        self.assertTrue(run_barebone(flatten(commands) + ['123456'], ["123456"], 1))
+
+    def test_constructors_global_and_assign(self):
+        commands = ['"global"',
+                        '"my_global"',
+                        'true',
+                    '"assign"',
+                        '"resolve"', '"my_global"',
+                        '"const"', '5',
+                        'true',
+                    '"output"',
+                        '"access"', '"resolve"', '"my_global"',
+                        'true',
+                    '"return"',
+                        'true',
+                        '"const"', "true",
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["5"], 1))
+
+    def test_constructors_funcdecl(self):
+        commands = ['"global"',
+                        '"my_global"',
+                        'true',
+                    '"funcdef"', '"my_global"',
+                        '2',
+                        2,
+                        3,
+                        '"return"', 'true',
+                            '"call"',
+                                '"deref"', '"primitives/integer_addition"',
+                                '2',
+                                '"access"', '"resolve"', 2,
+                                '"access"', '"resolve"', 3,
+                                'false',
+                        'true',
+                    '"output"',
+                        '"call"',
+                            '"access"', '"resolve"', '"my_global"',
+                            '2',
+                            '"input"',
+                            '"input"',
+                            'false',
+                        'true',
+                    '"return"', 'true',
+                        '"const"', 'true',
+                ]
+        self.assertTrue(run_barebone(flatten(commands) + ['2', '5'], ["7"], 1))
+
+    def test_constructors_fibonacci(self):
+        commands = ['"global"',
+                        '"fibonacci"',
+                        'true',
+                    '"funcdef"', '"fibonacci"',
+                        '1',
+                        2,
+                        '"if"',
+                            '"call"',
+                                '"deref"', '"primitives/integer_lte"',
+                                '2',
+                                '"access"', '"resolve"', 2,
+                                '"const"', '2',
+                                'false',
+                            '"return"', 'true', '"const"', '1',
+                            'true',
+                            '"return"', 'true',
+                                '"call"',
+                                    '"deref"', '"primitives/integer_addition"',
+                                    '2',
+                                    '"call"',
+                                        '"access"', '"resolve"', '"fibonacci"',
+                                        '1',
+                                        '"call"',
+                                            '"deref"', '"primitives/integer_subtraction"',
+                                            '2',
+                                            '"access"', '"resolve"', 2,
+                                            '"const"', '1',
+                                            'false',
+                                        'false',
+                                    '"call"',
+                                        '"access"', '"resolve"', '"fibonacci"',
+                                        '1',
+                                        '"call"',
+                                            '"deref"', '"primitives/integer_subtraction"',
+                                            '2',
+                                            '"access"', '"resolve"', 2,
+                                            '"const"', '2',
+                                            'false',
+                                        'false',
+                                    'false',
+                            'false',
+                        'true',
+                    '"while"',
+                        '"const"', 'true',
+                        '"output"',
+                            '"call"',
+                                '"access"', '"resolve"', '"fibonacci"',
+                                '1',
+                                '"input"',
+                                'false',
+                            'false',
+                        'false',
+                    ]
+        self.assertTrue(run_barebone(flatten(commands) + ['1', '2', '3', '4', '5', '6', '7', '8'], ['1', '1', '2', '3', '5', '8', '13', '21'], 1))
+
+    def test_constructors_continue(self):
+        commands = ['"while"',
+                        '"const"', 'true',
+                        '"output"', '"const"', '1',
+                            'true',
+                            '"if"',
+                                '"const"', 'true',
+                                '"continue"',
+                                'false',
+                                'true',
+                            '"output"', '"const"', '2',
+                                'false',
+                        'true',
+                    '"output"', '"const"', '3',
+                        'true',
+                    '"return"', 'true',
+                        '"const"', 'true',
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ['1', '1', '1', '1', '1'], 1))
+
+    def test_constructors_break(self):
+        commands = ['"while"',
+                        '"const"', 'true',
+                        '"output"', '"const"', '1',
+                            'true',
+                            '"if"',
+                                '"const"', 'true',
+                                '"break"',
+                                'false',
+                                'true',
+                            '"output"', '"const"', '2',
+                                'false',
+                        'true',
+                    '"output"', '"const"', '3',
+                        'true',
+                    '"return"', 'true',
+                        '"const"', 'true',
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ['1', '3'], 1))

+ 348 - 0
integration/test_constructors_al_linkable.py

@@ -0,0 +1,348 @@
+import unittest
+import sys
+import os
+
+from utils import execute, kill, run_file, run_barebone
+
+def extend_commands(commands):
+    # Initially we communicate with the compilation_manager to add the bytecodes
+    pre =   [
+                '3',
+                '"upload"',
+                '"test.o"',
+                '"MD5_HASH"',
+                'true',     # use NEW interface for constructors
+                '"funcdef"', '"main"', '0', # Main function
+            ]
+    # We only have to define "main" for now
+    post =  [
+                'true',
+                '"main"',
+                'true',
+                'false',
+            ]
+    return pre + commands + post
+
+class TestConstructorsActionLanguageLinkable(unittest.TestCase):
+    def test_constructors_simple(self):
+        commands = [
+                        '"output"',
+                            '"const"', 'true',
+                            'true',
+                        '"return"',
+                            'true',
+                            '"const"', 'true',
+                        'false',
+                    ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["True"], None, link=["test.o"]))
+
+    def test_constructors_if_else_true(self):
+        commands = [
+                        '"if"',                    # If
+                        '"const"', 'true',    # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'true',                 # Has else
+                        '"output"',            # False-part
+                            '"const"', 'false',
+                            'false',            # Has next
+                        'true',                 # Has next
+                        '"return"',            # Return
+                            'true',             # Has value
+                            '"const"', "true",
+                        'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["True"], None, link=["test.o"]))
+
+    def test_constructors_if_else_false(self):
+        commands = [
+                        '"if"',                    # If
+                        '"const"', 'false',   # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'true',                 # Has else
+                        '"output"',            # False-part
+                            '"const"', 'false',
+                            'false',            # Has next
+                        'true',                 # Has next
+                        '"return"',            # Return
+                            'true',             # Has value
+                            '"const"', "true",
+                        'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["False"], None, link=["test.o"]))
+
+    def test_constructors_if_true(self):
+        commands = [
+                        '"if"',                    # If
+                        '"const"', 'true',    # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'false',                # Has else
+                        'true',                 # Has next
+                        '"return"',            # Return
+                            'true',             # Has value
+                            '"const"', "true",
+                    'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["True"], None, link=["test.o"]))
+
+    def test_constructors_if_false(self):
+        commands = [
+                        '"if"',                    # If
+                        '"const"', 'false',   # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'false',                # Has else
+                        'true',                 # Has next
+                        '"return"',            # Return
+                            'true',             # Has value
+                            '"const"', "true",
+                        'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, [None], None, timeout=True, link=["test.o"]))
+
+    """
+    def test_constructors_addition(self):
+        commands = [('"output"',
+                        ('"call"',
+                            ('"deref"', '"primitives/integer_addition"'),
+                            '2',
+                            ('"const"', '1'),
+                            ('"const"', '5'),
+                            'false',
+                        ),
+                        'true',
+                        ('"return"', 'true', '"const"', 'true'),
+                    )
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ["6"], 1))
+    """
+
+    def test_constructors_while_false(self):
+        commands = [
+                        '"while"',                 # While
+                        '"const"', 'false',   # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'true',                 # Has next
+                        '"output"',            # Output false
+                            '"const"', 'false',
+                            'true',             # Has next
+                            '"return"',        # Return
+                                'true',         # Has value
+                                '"const"', "true",
+                        'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["False"], None, link=["test.o"]))
+
+    def test_constructors_while_true(self):
+        commands = [
+                        '"while"',                 # While
+                        '"const"', 'true',    # Condition
+                        '"output"',            # True-part
+                            '"const"', 'true',
+                            'false',            # Has next
+                        'true',                 # Has next
+                        '"output"',            # False-part
+                            '"const"', 'false',
+                            'true',            # Has next
+                        '"return"',            # Return
+                            'true',             # Has value
+                            '"const"', "true",
+                        'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["True", "True", "True", "True"], None, link=["test.o"]))
+
+    def test_constructors_declare_and_assign(self):
+        commands = [
+                    '"declare"',
+                        1,
+                        'true',
+                    '"assign"',
+                        '"resolve"', 1,
+                        '"const"', '5',
+                        'true',
+                    '"output"',
+                        '"access"', '"resolve"', 1,
+                        'true',
+                    '"return"',
+                        'true',
+                        '"const"', "true",
+                    'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["5"], None, link=["test.o"]))
+
+    """
+    def test_constructors_output_input(self):
+        commands = [
+                     '"output"',
+                        '"input"',
+                        'true',
+                    '"return"',
+                        'true',
+                        '"const"', "true",
+                    'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands + ['123456'], ["123456"], None, link=["test.o"]))
+    """
+
+    def test_constructors_global_and_assign(self):
+        commands = [
+                    '"global"',
+                        '"my_global"',
+                        'true',
+                    '"assign"',
+                        '"resolve"', '"my_global"',
+                        '"const"', '5',
+                        'true',
+                    '"output"',
+                        '"access"', '"resolve"', '"my_global"',
+                        'true',
+                    '"return"',
+                        'true',
+                        '"const"', "true",
+                    'false',
+                ]
+        commands = extend_commands(commands)
+        self.assertTrue(run_barebone(commands, ["5"], None, link=["test.o"]))
+
+    """
+    def test_constructors_funcdecl(self):
+        commands = ['"global"',
+                        '"my_global"',
+                        'true',
+                    '"funcdef"', '"my_global"',
+                        '2',
+                        2,
+                        3,
+                        '"return"', 'true',
+                            '"call"',
+                                '"deref"', '"primitives/integer_addition"',
+                                '2',
+                                '"access"', '"resolve"', 2,
+                                '"access"', '"resolve"', 3,
+                                'false',
+                        'true',
+                    '"output"',
+                        '"call"',
+                            '"access"', '"resolve"', '"my_global"',
+                            '2',
+                            '"input"',
+                            '"input"',
+                            'false',
+                        'true',
+                    '"return"', 'true',
+                        '"const"', 'true',
+                ]
+        self.assertTrue(run_barebone(flatten(commands) + ['2', '5'], ["7"], 1))
+
+    def test_constructors_fibonacci(self):
+        commands = ['"global"',
+                        '"fibonacci"',
+                        'true',
+                    '"funcdef"', '"fibonacci"',
+                        '1',
+                        2,
+                        '"if"',
+                            '"call"',
+                                '"deref"', '"primitives/integer_lte"',
+                                '2',
+                                '"access"', '"resolve"', 2,
+                                '"const"', '2',
+                                'false',
+                            '"return"', 'true', '"const"', '1',
+                            'true',
+                            '"return"', 'true',
+                                '"call"',
+                                    '"deref"', '"primitives/integer_addition"',
+                                    '2',
+                                    '"call"',
+                                        '"access"', '"resolve"', '"fibonacci"',
+                                        '1',
+                                        '"call"',
+                                            '"deref"', '"primitives/integer_subtraction"',
+                                            '2',
+                                            '"access"', '"resolve"', 2,
+                                            '"const"', '1',
+                                            'false',
+                                        'false',
+                                    '"call"',
+                                        '"access"', '"resolve"', '"fibonacci"',
+                                        '1',
+                                        '"call"',
+                                            '"deref"', '"primitives/integer_subtraction"',
+                                            '2',
+                                            '"access"', '"resolve"', 2,
+                                            '"const"', '2',
+                                            'false',
+                                        'false',
+                                    'false',
+                            'false',
+                        'true',
+                    '"while"',
+                        '"const"', 'true',
+                        '"output"',
+                            '"call"',
+                                '"access"', '"resolve"', '"fibonacci"',
+                                '1',
+                                '"input"',
+                                'false',
+                            'false',
+                        'false',
+                    ]
+        self.assertTrue(run_barebone(flatten(commands) + ['1', '2', '3', '4', '5', '6', '7', '8'], ['1', '1', '2', '3', '5', '8', '13', '21'], 1))
+
+    def test_constructors_continue(self):
+        commands = ['"while"',
+                        '"const"', 'true',
+                        '"output"', '"const"', '1',
+                            'true',
+                            '"if"',
+                                '"const"', 'true',
+                                '"continue"',
+                                'false',
+                                'true',
+                            '"output"', '"const"', '2',
+                                'false',
+                        'true',
+                    '"output"', '"const"', '3',
+                        'true',
+                    '"return"', 'true',
+                        '"const"', 'true',
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ['1', '1', '1', '1', '1'], 1))
+    def test_constructors_break(self):
+        commands = ['"while"',
+                        '"const"', 'true',
+                        '"output"', '"const"', '1',
+                            'true',
+                            '"if"',
+                                '"const"', 'true',
+                                '"break"',
+                                'false',
+                                'true',
+                            '"output"', '"const"', '2',
+                                'false',
+                        'true',
+                    '"output"', '"const"', '3',
+                        'true',
+                    '"return"', 'true',
+                        '"const"', 'true',
+                ]
+        self.assertTrue(run_barebone(flatten(commands), ['1', '3'], 1))
+    """

Plik diff jest za duży
+ 1933 - 0
integration/test_constructors_models.py


+ 17 - 0
integration/test_factorial.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestFactorial(unittest.TestCase):
+    def test_po_factorial(self):
+        self.factorial("PO")
+
+    def test_co_factorial(self):
+        self.factorial("CO")
+
+    def factorial(self, mode):
+        self.assertTrue(run_file(["factorial.alc", "primitives.alc"],
+            [1, 2, 3, 4],
+            ["1", "2", "6", "24"],
+            mode))

+ 17 - 0
integration/test_fibonacci.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestFibonacci(unittest.TestCase):
+    def test_po_fibonacci(self):
+        self.fibonacci("PO")
+
+    def test_co_fibonacci(self):
+        self.fibonacci("CO")
+
+    def fibonacci(self, mode):
+        self.assertTrue(run_file(["fibonacci.alc", "primitives.alc"],
+            [1, 2, 3, 4],
+            ["1", "1", "2", "3"],
+            mode))

+ 17 - 0
integration/test_fibonacci_smart.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestFibonacciSmart(unittest.TestCase):
+    def test_po_fibonacci_smart(self):
+        self.fibonacci_smart("PO")
+
+    def test_co_fibonacci_smart(self):
+        self.fibonacci_smart("CO")
+
+    def fibonacci_smart(self, mode):
+        self.assertTrue(run_file(["fibonacci_smart.alc", "primitives.alc"],
+            [1, 2, 3, 4, 5, 6, 7, 8],
+            ["1", "1", "2", "3", "5", "8", "13", "21"],
+            mode))

+ 29 - 0
integration/test_if_elif.py

@@ -0,0 +1,29 @@
+import unittest
+
+from utils import run_file
+
+
+class TestIfElif(unittest.TestCase):
+    def test_po_if_elif_else(self):
+        self.if_elif_else("PO")
+
+    def test_co_if_elif_else(self):
+        self.if_elif_else("CO")
+
+    def if_elif_else(self, mode):
+        self.assertTrue(run_file(["if_elif_else.alc", "primitives.alc"],
+            [-1,   10,  11,  0,   1,   0,   -100],
+            ["-1", "1", "1", "0", "1", "0", "-1"],
+            mode))
+
+    def test_po_if_elif(self):
+        self.if_elif("PO")
+
+    def test_co_if_elif(self):
+        self.if_elif("CO")
+
+    def if_elif(self, mode):
+        self.assertTrue(run_file(["if_elif.alc", "primitives.alc"],
+                                 [-1, 10, 11, 0, 1, 0, -100],
+                                 ["-1", "1", "1", "0", "1", "0", "-1"],
+                                 mode))

+ 17 - 0
integration/test_leap_year.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestLeapYear(unittest.TestCase):
+    def test_po_leap_year(self):
+        self.leap_year("PO")
+
+    def test_co_leap_year(self):
+        self.leap_year("CO")
+
+    def leap_year(self, mode):
+        self.assertTrue(run_file(["leap_year.alc", "primitives.alc"],
+            [  2016,    2015,    2014,    2013,   2012,    2001,    2000,    1999],
+            ["True", "False", "False", "False", "True", "False", "False", "False"],
+            mode))

+ 17 - 0
integration/test_main.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestMain(unittest.TestCase):
+    def test_po_main(self):
+        self.main("PO")
+
+    def test_co_main(self):
+        self.main("CO")
+
+    def main(self, mode):
+        self.assertTrue(run_file(["main.alc", "primitives.alc"],
+            [],
+            ["Hello, world!", "Hello, world!", "Hello, world!"],
+            mode))

+ 672 - 0
integration/test_pn_interface.py

@@ -0,0 +1,672 @@
+import unittest
+
+from utils import run_file
+
+all_files = [   "pn_interface.alc",
+                "primitives.alc",
+                "object_operations.alc",
+                "conformance_scd.alc",
+                "library.alc",
+                "constructors.alc",
+                "--fast",
+            ]
+
+greeting =          ["Welcome to the Model Management Interface, running live"
+                     " on the Modelverse!",
+                     "Use 'help' command for a list of possible commands"]
+new =               ["Metamodel to instantiate?", "Name of model?"]
+new_fail =          ["Model exists; aborting"]
+loaded =            ["Model loaded, ready for commands!",
+                     "Use 'help' command for a list of possible commands"]
+prompt_menu =       ["Please give your command."]
+prompt_model =      ["Please give your command."]
+load =              ["Model to load?"]
+load_fail =         ["Model not found; aborting"]
+instantiate =       ["Type to instantiate?"]
+instantiate_name =  ["Name of new element?"]
+instantiate_tokens= ["tokens : Integer?"]
+instantiate_ok =    ["Instantiation successful!"]
+instantiate_source= ["Source name?"]
+instantiate_destination = ["Destination name?"]
+instantiate_weight= ["weight : Integer?"]
+list_menu =         ["Found models:"]
+list_all =          set(["  PetriNets : SimpleClassDiagrams",
+                         "  SimpleClassDiagrams : SimpleClassDiagrams",
+                         "  LTM_bottom : LTM_bottom"])
+list_empty =        list_menu + [list_all]
+list_abc =          ["  abc : PetriNets"]
+list_def =          ["  def : PetriNets"]
+list_model =        ["List of all elements:"]
+list_p1 =           ["  p1 : Place"]
+list_p2 =           ["  p2 : Place"]
+list_t1 =           ["  t1 : Transition"]
+list_p2t =          ["  p2t : P2T"]
+list_t2p =          ["  t2p : T2P"]
+read =              ["Element to read?"]
+read_p1 =           ["Name: p1",
+                     "Type: Place",
+                     "Defines attributes:",
+                     "Attributes:",
+                     "   tokens : Integer = 5"]
+read_p1_1 =         ["Name: p1",
+                     "Type: Place",
+                     "Defines attributes:",
+                     "Attributes:",
+                     "   tokens : Integer = 1"]
+read_p2 =           ["Name: p2",
+                     "Type: Place",
+                     "Defines attributes:",
+                     "Attributes:",
+                     "   tokens : Integer = 0"]
+read_t1 =           ["Name: t1",
+                     "Type: Transition",
+                     "Defines attributes:",
+                     "Attributes:"]
+read_p2t =          ["Name: p2t",
+                     "Type: P2T",
+                     "Source: p1",
+                     "Destination: t1",
+                     "Defines attributes:",
+                     "Attributes:",
+                     "   weight : Integer = 2"]
+read_t2p =          ["Name: t2p",
+                     "Type: T2P",
+                     "Source: t1",
+                     "Destination: p2",
+                     "Defines attributes:",
+                     "Attributes:",
+                     "   weight : Integer = 1"]
+read_fail =         ["Unknown element; aborting"]
+enabled =           ["Enabled transitions:"]
+enabled_t1 =        ["t1"]
+fire =              ["Transition to fire?"]
+fire_t1 =           ["  p1: 3",
+                     "  p2: 1"]
+fire_finish =       ["Transition fired!"]
+fire_unknown =      ["Unknown transition; aborting"]
+fire_no_enable =    ["Cannot fire if not enabled; aborting"]
+delete =            ["Model to delete?"]
+delete_ok =         ["Deleted!"]
+delete_fail =       ["Model not found; aborting"]
+rename_old =        ["Old name?"]
+rename_new =        ["New name?"]
+rename_ok =         ["Rename complete!"]
+rename_fail_not_exists = ["Model not found; aborting"]
+rename_fail_exists= ["Model exists; aborting"]
+rename_model_old =  ["Old name?"]
+rename_model_new =  ["New name?"]
+rename_model_ok =   ["Rename complete!"]
+rename_model_fail_not_exists = ["Unknown element; aborting"]
+rename_model_fail_exists= ["New name already used; aborting"]
+help_msg =          ["Currently no model is loaded, so your operations are "
+                     "limited to:",
+                     "  new    -- Create a new model and save it for future "
+                     "use",
+                     "  load   -- Load a previously made model",
+                     "  rename -- Rename a previously made model",
+                     "  delete -- Delete a previously made model",
+                     "  list   -- Show a list of all stored models",
+                     "  help   -- Show a list of possible commands"]
+verify_ok =         ["OK"]
+verify_fail_weight= ["Negative weight in arc p2t"]
+verify_fail_tokens= ["Negative number of tokens in Place p1"]
+verify_fail_structure = ["Source of model edge not typed by source of type: "
+                         "p2t"]
+list_types =        ["List of types:",
+                     "  Place : Class",
+                     "  Transition : Class",
+                     "  P2T : Association",
+                     "  T2P : Association"]
+modify =            ["Element to modify?"]
+modify_place =      ["   tokens : Integer"]
+modify_arc =        ["   weight : Integer"]
+modify_attribute =  ["Attribute to modify?"]
+modify_value =      ["New value?",
+                     "Modified!"]
+modify_fail_not_exists = ["Element does not exist; aborting"]
+modify_fail_no_attr=["Unknown attribute; aborting"]
+
+instantiate_place = instantiate + instantiate_name + instantiate_tokens +\
+                    instantiate_ok + prompt_model
+instantiate_transition = instantiate + instantiate_name + instantiate_ok +\
+                         prompt_model
+instantiate_arc = instantiate + instantiate_name + instantiate_source +\
+                  instantiate_destination + instantiate_weight +\
+                  instantiate_ok + prompt_model
+read_p1_full = read + read_p1 + prompt_model
+read_p2_full = read + read_p2 + prompt_model
+read_p1_as_p2 = read + [v.replace("p1", "p2") for v in read_p1] + prompt_model
+read_t1_full = read + read_t1 + prompt_model
+read_p2t_full = read + read_p2t + prompt_model
+read_t2p_full = read + read_t2p + prompt_model
+new_full = new + loaded + prompt_model
+delete_full = delete + delete_ok + prompt_menu
+init = greeting + prompt_menu
+rename_full = rename_old + rename_new + rename_ok + prompt_menu
+rename_model_full = rename_model_old + rename_model_new + rename_model_ok +\
+                    prompt_model
+help_full = help_msg + prompt_menu
+load_full = load + loaded + prompt_model
+verify_full = verify_ok + prompt_model
+types_full = list_types + prompt_model
+modify_place_full = modify + modify_place + modify_attribute + modify_value +\
+                    prompt_model
+
+
+class TestPetrinetInterface(unittest.TestCase):
+    def test_po_pn_interface_new(self):
+        self.pn_interface_new("PO")
+
+    def test_co_pn_interface_new(self):
+        self.pn_interface_new("CO")
+
+    def pn_interface_new(self, mode):
+        self.assertTrue(run_file(all_files, ["new", "PetriNets", "abc"],
+            init + new_full, mode))
+
+    def test_po_pn_interface_help(self):
+        self.pn_interface_help("PO")
+
+    def test_co_pn_interface_help(self):
+        self.pn_interface_help("CO")
+
+    def pn_interface_help(self, mode):
+        self.assertTrue(run_file(all_files, ["help"],
+            init + help_full, mode))
+
+    def test_po_pn_interface_list_empty(self):
+        self.pn_interface_list_empty("PO")
+
+    def test_co_pn_interface_list_empty(self):
+        self.pn_interface_list_empty("CO")
+
+    def pn_interface_list_empty(self, mode):
+        self.assertTrue(run_file(all_files, ["list"],
+            init + list_empty + prompt_model, mode))
+
+    def test_po_pn_interface_list_one(self):
+        self.pn_interface_list_one("PO")
+
+    def test_co_pn_interface_list_one(self):
+        self.pn_interface_list_one("CO")
+
+    def pn_interface_list_one(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "list"], init + new_full + prompt_menu +
+            list_menu + [set(list_abc).union(list_all)] + prompt_menu, mode))
+
+    def test_po_pn_interface_list_two(self):
+        self.pn_interface_list_two("PO")
+
+    def test_co_pn_interface_list_two(self):
+        self.pn_interface_list_two("CO")
+
+    def pn_interface_list_two(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "new", "PetriNets", "def", "exit", "list"],
+            init + new_full + prompt_menu + new_full + prompt_menu +
+            list_menu + [set(list_abc).union(set(list_def)).union(list_all)] + prompt_menu, mode))
+
+    def test_po_pn_interface_rename(self):
+        self.pn_interface_rename("PO")
+
+    def test_co_pn_interface_rename(self):
+        self.pn_interface_rename("CO")
+
+    def pn_interface_rename(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "list", "rename", "abc", "def", "list",
+            "load", "abc", "load", "def", "exit", "list"],
+            init + new_full + prompt_menu + list_menu + [set(list_abc).union(list_all)] +
+            prompt_menu + rename_full + list_menu + [set(list_def).union(list_all)] + prompt_menu +
+            load + load_fail + prompt_menu + load_full + prompt_menu +
+            list_menu + [set(list_def).union(list_all)] + prompt_menu, mode))
+
+    def test_po_pn_interface_rename_fail_not_exists(self):
+        self.pn_interface_rename_fail_not_exists("PO")
+
+    def test_co_pn_interface_rename_fail_not_exists(self):
+        self.pn_interface_rename_fail_not_exists("CO")
+
+    def pn_interface_rename_fail_not_exists(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "list", "rename", "def", "list", "load",
+            "abc", "exit", "load", "def", "list"],
+            init + new_full + prompt_menu + list_menu + [set(list_abc).union(list_all)] +
+            prompt_menu + rename_old + rename_fail_not_exists + prompt_menu +
+            list_menu + [set(list_abc).union(list_all)] + prompt_menu + load_full + prompt_menu +
+            load + load_fail + prompt_menu + list_menu + [set(list_abc).union(list_all)] +
+            prompt_menu, mode))
+
+    def test_po_pn_interface_delete_only(self):
+        self.pn_interface_delete_only("PO")
+
+    def test_co_pn_interface_delete_only(self):
+        self.pn_interface_delete_only("CO")
+
+    def pn_interface_delete_only(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "delete", "abc", "list"],
+            init + new_full + prompt_menu + delete_full + list_empty +
+            prompt_menu, mode))
+
+    def test_po_pn_interface_delete(self):
+        self.pn_interface_delete("PO")
+
+    def test_co_pn_interface_delete(self):
+        self.pn_interface_delete("CO")
+
+    def pn_interface_delete(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "new", "PetriNets", "def", "exit", "delete", "abc",
+            "list"], init + new_full + prompt_menu + new_full + prompt_menu +
+            delete_full + list_menu + [set(list_def).union(list_all)] + prompt_menu, mode))
+
+    def test_po_pn_interface_delete_fail(self):
+        self.pn_interface_delete_fail("PO")
+
+    def test_co_pn_interface_delete_fail(self):
+        self.pn_interface_delete_fail("CO")
+
+    def pn_interface_delete_fail(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "delete", "def", "list"],
+            init + new_full + prompt_menu + delete + delete_fail +
+            prompt_menu + list_menu + [set(list_abc).union(list_all)] + prompt_menu, mode))
+
+    def test_po_pn_interface_new_reload(self):
+        self.pn_interface_new_reload("PO")
+
+    def test_co_pn_interface_new_reload(self):
+        self.pn_interface_new_reload("CO")
+
+    def pn_interface_new_reload(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "load", "abc"], init + new_full +
+            prompt_menu + load_full, mode))
+
+    def test_po_pn_interface_new_fail(self):
+        self.pn_interface_new_fail("PO")
+
+    def test_co_pn_interface_new_fail(self):
+        self.pn_interface_new_fail("CO")
+
+    def pn_interface_new_fail(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "new", "PetriNets", "abc"], init + new_full +
+            prompt_menu + new + new_fail + prompt_menu, mode))
+
+    def test_po_pn_interface_load_fail(self):
+        self.pn_interface_load_fail("PO")
+
+    def test_co_pn_interface_load_fail(self):
+        self.pn_interface_load_fail("CO")
+
+    def pn_interface_load_fail(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "exit", "load", "def"], init + new_full +
+            prompt_menu + load + load_fail + prompt_menu, mode))
+
+    def test_po_pn_interface_load_empty(self):
+        self.pn_interface_load_empty("PO")
+
+    def test_co_pn_interface_load_empty(self):
+        self.pn_interface_load_empty("CO")
+
+    def pn_interface_load_empty(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["load", "def"], init + load + load_fail + prompt_menu, mode))
+
+    def test_po_pn_interface_new_list_empty(self):
+        self.pn_interface_new_list_empty("PO")
+
+    def test_co_pn_interface_new_list_empty(self):
+        self.pn_interface_new_list_empty("CO")
+
+    def pn_interface_new_list_empty(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "list"], init + new_full + list_model +
+            prompt_model, mode))
+
+    def test_po_pn_interface_instantiate_place(self):
+        self.pn_interface_instantiate_place("PO")
+
+    def test_co_pn_interface_instantiate_place(self):
+        self.pn_interface_instantiate_place("CO")
+
+    def pn_interface_instantiate_place(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model, mode))
+
+    def test_po_pn_interface_instantiate_place_list(self):
+        self.pn_interface_instantiate_place_list("PO")
+
+    def test_co_pn_interface_instantiate_place_list(self):
+        self.pn_interface_instantiate_place_list("CO")
+
+    def pn_interface_instantiate_place_list(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "list"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model +
+            list_model + list_p1, mode))
+
+    def test_po_pn_interface_instantiate_place_read(self):
+        self.pn_interface_instantiate_place_read("PO")
+
+    def test_co_pn_interface_instantiate_place_read(self):
+        self.pn_interface_instantiate_place_read("CO")
+
+    def pn_interface_instantiate_place_read(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "read", "p1"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model + read +
+            read_p1, mode))
+
+    def test_po_pn_interface_instantiate_transition(self):
+        self.pn_interface_instantiate_transition("PO")
+
+    def test_co_pn_interface_instantiate_transition(self):
+        self.pn_interface_instantiate_transition("CO")
+
+    def pn_interface_instantiate_transition(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_ok + prompt_model, mode))
+
+    def test_po_pn_interface_instantiate_transition_read(self):
+        self.pn_interface_instantiate_transition_read("PO")
+
+    def test_co_pn_interface_instantiate_transition_read(self):
+        self.pn_interface_instantiate_transition_read("CO")
+
+    def pn_interface_instantiate_transition_read(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "read", "t1"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_ok + prompt_model + read + read_t1, mode))
+
+    def test_po_pn_interface_instantiate_arcs(self):
+        self.pn_interface_instantiate_arcs("PO")
+
+    def test_co_pn_interface_instantiate_arcs(self):
+        self.pn_interface_instantiate_arcs("CO")
+
+    def pn_interface_instantiate_arcs(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc, mode))
+
+    def test_po_pn_interface_instantiate_arcs_read(self):
+        self.pn_interface_instantiate_arcs_read("PO")
+
+    def test_co_pn_interface_instantiate_arcs_read(self):
+        self.pn_interface_instantiate_arcs_read("CO")
+
+    def pn_interface_instantiate_arcs_read(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1, "read", "p1", "read", "p2", "read", "t1", "read", "p2t",
+             "read", "t2p"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc +
+            read_p1_full + read_p2_full + read_t1_full + read_p2t_full +
+            read_t2p_full, mode))
+
+    def test_po_pn_interface_instantiate_arcs_list(self):
+        self.pn_interface_instantiate_arcs_list("PO")
+
+    def test_co_pn_interface_instantiate_arcs_list(self):
+        self.pn_interface_instantiate_arcs_list("CO")
+
+    def pn_interface_instantiate_arcs_list(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1, "list"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc +
+            list_model + list_t1 + list_p1 + list_p2 + list_p2t + list_t2p +
+            prompt_model, mode))
+
+    def test_po_pn_interface_enabled_empty(self):
+        self.pn_interface_enabled_empty("PO")
+
+    def test_co_pn_interface_enabled_empty(self):
+        self.pn_interface_enabled_empty("CO")
+
+    def pn_interface_enabled_empty(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "enabled"],
+            init + new_full + enabled + prompt_model, mode))
+
+    def test_po_pn_interface_enabled(self):
+        self.pn_interface_enabled("PO")
+
+    def test_co_pn_interface_enabled(self):
+        self.pn_interface_enabled("CO")
+
+    def pn_interface_enabled(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1, "enabled"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc + enabled +
+            enabled_t1 + prompt_model, mode))
+
+    def test_po_pn_interface_fire(self):
+        self.pn_interface_fire("PO")
+
+    def test_co_pn_interface_fire(self):
+        self.pn_interface_fire("CO")
+
+    def pn_interface_fire(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1, "fire", "t1"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc + fire +
+            fire_t1 + fire_finish + prompt_model, mode))
+
+    def test_po_pn_interface_fire_place(self):
+        self.pn_interface_fire_place("PO")
+
+    def test_co_pn_interface_fire_place(self):
+        self.pn_interface_fire_place("CO")
+
+    def pn_interface_fire_place(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", "5", "fire", "p1"],
+            init + new_full + instantiate_place + fire + fire_no_enable +
+            prompt_model, mode))
+
+    def test_po_pn_interface_fire_unknown(self):
+        self.pn_interface_fire_unknown("PO")
+
+    def test_co_pn_interface_fire_unknown(self):
+        self.pn_interface_fire_unknown("CO")
+
+    def pn_interface_fire_unknown(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "fire", "t1"],
+            init + new_full + fire + fire_unknown + prompt_model, mode))
+
+    def test_po_pn_interface_verify_OK(self):
+        self.pn_interface_verify_OK("PO")
+
+    def test_co_pn_interface_verify_OK(self):
+        self.pn_interface_verify_OK("CO")
+
+    def pn_interface_verify_OK(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1, "verify"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc +
+            verify_full, mode))
+
+    def test_po_pn_interface_verify_fail_tokens(self):
+        self.pn_interface_verify_fail_tokens("PO")
+
+    def test_co_pn_interface_verify_fail_tokens(self):
+        self.pn_interface_verify_fail_tokens("CO")
+
+    def pn_interface_verify_fail_tokens(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", -5, "instantiate", "Place", "p2", 0,
+             "instantiate", "P2T", "p2t", "p1", "t1", 2, "instantiate", "T2P",
+             "t2p", "t1", "p2", 1, "verify"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + instantiate_arc +
+            verify_fail_tokens, mode))
+
+    def test_po_pn_interface_verify_fail_weight(self):
+        self.pn_interface_verify_fail_weight("PO")
+
+    def test_co_pn_interface_verify_fail_weight(self):
+        self.pn_interface_verify_fail_weight("CO")
+
+    def pn_interface_verify_fail_weight(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "p1", "t1", -2, "instantiate", "T2P", "t2p", "t1",
+             "p2", 1, "verify"], init + new_full + instantiate_transition +
+            instantiate_place + instantiate_place + instantiate_arc +
+            instantiate_arc + verify_fail_weight, mode))
+
+    def test_po_pn_interface_verify_fail_structure(self):
+        self.pn_interface_verify_fail_structure("PO")
+
+    def test_co_pn_interface_verify_fail_structure(self):
+        self.pn_interface_verify_fail_structure("CO")
+
+    def pn_interface_verify_fail_structure(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Transition", "t1", "instantiate",
+             "Place", "p1", 5, "instantiate", "Place", "p2", 0, "instantiate",
+             "P2T", "p2t", "t1", "p1", 2, "verify"],
+            init + new_full + instantiate_transition + instantiate_place +
+            instantiate_place + instantiate_arc + verify_fail_structure,
+            mode))
+
+    def test_po_pn_interface_types(self):
+        self.pn_interface_types("PO")
+
+    def test_co_pn_interface_types(self):
+        self.pn_interface_types("CO")
+
+    def pn_interface_types(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "types"], init + new_full + types_full, mode))
+
+    def test_po_pn_interface_modify_place(self):
+        self.pn_interface_modify_place("PO")
+
+    def test_co_pn_interface_modify_place(self):
+        self.pn_interface_modify_place("CO")
+
+    def pn_interface_modify_place(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "read", "p1",
+             "modify", "p1", "tokens", 1, "read", "p1"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model + read +
+            read_p1 + prompt_menu + modify_place_full + read + read_p1_1 +
+            prompt_menu, mode))
+
+    def test_po_pn_interface_modify_unknown(self):
+        self.pn_interface_modify_unknown("PO")
+
+    def test_co_pn_interface_modify_unknown(self):
+        self.pn_interface_modify_unknown("CO")
+
+    def pn_interface_modify_unknown(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "modify", "p1"],
+            init + new_full + modify + modify_fail_not_exists + prompt_model,
+            mode))
+
+    def test_po_pn_interface_modify_place_attr(self):
+        self.pn_interface_modify_place_attr("PO")
+
+    def test_co_pn_interface_modify_place_attr(self):
+        self.pn_interface_modify_place_attr("CO")
+
+    def pn_interface_modify_place_attr(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "read", "p1",
+             "modify", "p1", "tok", "read", "p1"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model + read +
+            read_p1 + prompt_menu + modify + modify_place + modify_attribute +
+            modify_fail_no_attr + prompt_model + read + read_p1 +
+            prompt_model, mode))
+
+    def test_po_pn_interface_rename_place(self):
+        self.pn_interface_rename_place("PO")
+
+    def test_co_pn_interface_rename_place(self):
+        self.pn_interface_rename_place("CO")
+
+    def pn_interface_rename_place(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "rename", "p1",
+             "p2", "read", "p1", "read", "p2"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model +
+            rename_model_full + read + read_fail + prompt_model +
+            read_p1_as_p2, mode))
+
+    def test_po_pn_interface_rename_exists(self):
+        self.pn_interface_rename_exists("PO")
+
+    def test_co_pn_interface_rename_exists(self):
+        self.pn_interface_rename_exists("CO")
+
+    def pn_interface_rename_exists(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "instantiate",
+             "Place", "p2", 0, "rename", "p1", "p2", "read", "p1", "read",
+             "p2"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model +
+            instantiate + instantiate_name + instantiate_tokens +
+            instantiate_ok + prompt_model + rename_model_old +
+            rename_model_new + rename_model_fail_exists + prompt_model +
+            read + read_p1 + prompt_model + read + read_p2 + prompt_model,
+            mode))
+
+    def test_po_pn_interface_rename_not_exists(self):
+        self.pn_interface_rename_not_exists("PO")
+
+    def test_co_pn_interface_rename_not_exists(self):
+        self.pn_interface_rename_not_exists("CO")
+
+    def pn_interface_rename_not_exists(self, mode):
+        self.assertTrue(run_file(all_files,
+            ["new", "PetriNets", "abc", "instantiate", "Place", "p1", 5, "rename", "p2",
+             "read", "p1", "read", "p2"],
+            init + new_full + instantiate + instantiate_name +
+            instantiate_tokens + instantiate_ok + prompt_model +
+            rename_model_old + rename_model_fail_not_exists + prompt_model +
+            read_p1_full + read + read_fail + prompt_model, mode))
+

+ 16 - 0
integration/test_power.py

@@ -0,0 +1,16 @@
+import unittest
+
+from utils import run_file
+
+
+class TestPower(unittest.TestCase):
+    def test_po_power(self):
+        self.power("PO")
+
+    def test_cs_power(self):
+        self.power("CO")
+
+    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", "2", "1", "4", "9", "100", "10000000000"], mode))

+ 16 - 0
integration/test_remainder.py

@@ -0,0 +1,16 @@
+import unittest
+
+from utils import run_file
+
+
+class TestRemainder(unittest.TestCase):
+    def test_po_remainder(self):
+        self.remainder("PO")
+
+    def test_cs_remainder(self):
+        self.remainder("CO")
+
+    def remainder(self, mode):
+        self.assertTrue(run_file(["remainder.alc", "primitives.alc"],
+            [(1, 2), (20, 2), (99, 100), (17, 3)],
+            ["1", "0", "99", "2"], mode))

+ 17 - 0
integration/test_revert.py

@@ -0,0 +1,17 @@
+import unittest
+
+from utils import run_file
+
+
+class TestRevert(unittest.TestCase):
+    def test_po_revert(self):
+        self.revert("PO")
+
+    def test_cs_revert(self):
+        self.revert("CO")
+
+    def revert(self, mode):
+        self.assertTrue(run_file(["revert.alc", "primitives.alc"],
+            ["abc", "defghi", "This is a very simple test case!", "abccba"],
+            ["cba", "ihgfed", "!esac tset elpmis yrev a si sihT", "abccba"],
+            mode))

+ 216 - 0
integration/utils.py

@@ -0,0 +1,216 @@
+import unittest
+import sys
+import os
+
+import sys
+import time
+import json
+import urllib
+import urllib2
+import subprocess
+import signal
+
+username = "test_user"
+
+def serialize(value):
+    if isinstance(value, str):
+        return '"%s"' % value
+    else:
+        return str(value)
+
+def execute(scriptname, parameters=[], wait=False):
+    if os.name == "nt":
+        command = ["%s.bat" % scriptname] + parameters
+    elif os.name == "posix":
+        command = ["./%s.sh" % scriptname] + parameters
+    else:
+        raise Exception("Unknown OS: " + str(os.name))
+
+    if wait:
+        return subprocess.call(command, shell=False)
+    else:
+        return subprocess.Popen(command, shell=False)
+
+def kill(process):
+    if os.name == "nt":
+        subprocess.call(["taskkill", "/F", "/T", "/PID", "%i" % process.pid])
+    elif os.name == "posix":
+        subprocess.call(["pkill", "-P", "%i" % process.pid])
+
+def flush_data(data):
+    if data:
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "data": json.dumps(data), "username": username})), timeout=10).read()
+    return []
+
+def run_file(files, parameters, expected, mode):
+    # Resolve file
+    import os.path
+
+    time.sleep(0.01)
+    try:
+        # Run Modelverse server
+        proc = execute("run_local_modelverse", ["bootstrap/bootstrap.m"], wait=False)
+
+        try:
+            for filename in files:
+                if filename == "--fast":
+                    continue
+                if os.path.isfile("integration/code/%s" % filename):
+                    mod_filename = "integration/code/%s" % filename
+                elif os.path.isfile("bootstrap/%s" % filename):
+                    mod_filename = "bootstrap/%s" % filename
+                else:
+                    raise Exception("File not found: %s" % filename)
+                print("Found file " + str(mod_filename))
+
+                # Load in the file required
+                timeout_val = 120
+                while 1:
+                    proc2 = execute("compile", [mod_filename, username, filename, mode], wait=False)
+
+                    while proc2.returncode is None:
+                        time.sleep(0.01)
+                        proc2.poll()
+                        timeout_val -= 0.01
+                        if timeout_val < 0:
+                            kill(proc2)
+                            print("Compilation timeout expired!")
+                            return False
+                    if proc2.returncode != 7:
+                        break
+
+                # Make sure everything stopped correctly
+                assert proc2.returncode == 0
+                if proc2.returncode != 0:
+                    return False
+
+            if mode[-1] == "O":
+                # Fire up the linker
+                val = execute("link_and_load", [username] + files, wait=True)
+                if val != 0:
+                    raise Exception("Linking error")
+
+            # Send in the actual request and wait for replies
+            data = []
+            for p in parameters:
+                if isinstance(p, tuple):
+                    for v in p:
+                        data.append(["V", serialize(v)])
+                else:
+                    data.append(["V", serialize(p)])
+            flush_data(data)
+            
+            for e in expected:
+                c = len(e) if isinstance(e, set) else 1
+                for _ in range(c):
+                    val = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username})), timeout=10).read()
+                    val = val.split("=", 2)[2]
+                    print("Got %s, expect %s" % (val, e))
+                    if isinstance(e, set):
+                        assert str(val) in e
+                        if str(val) not in e:
+                            return False
+                    else:
+                        assert str(val) == e
+                        if str(val) != e:
+                            return False
+
+            # All passed!
+            return True
+        except:
+            raise
+        finally:
+            try:
+                kill(proc2)
+            except UnboundLocalError:
+                pass
+    except:
+        raise
+    finally:
+        try:
+            kill(proc)
+        except UnboundLocalError:
+            pass
+            
+def run_barebone(parameters, expected, interface="0", timeout=False, wait=False, link=None):
+    try:
+        # Run Modelverse server
+        proc = execute("run_local_modelverse", ["bootstrap/bootstrap.m"], wait=False)
+
+        # Create user and set interface
+        timeout_val = 15
+        start = time.time()
+        while 1:
+            try:
+                urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % username, "username": "user_manager"})), timeout=1).read()
+                if interface is not None:
+                    urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": interface, "username": username})), timeout=1).read()
+                break
+            except:
+                time.sleep(0.01)
+                if time.time() - start > timeout_val:
+                    raise
+
+        # Send in the actual request and wait for replies
+        var_list = {}
+        data = []
+        for p in parameters:
+            if isinstance(p, int):
+                if p not in var_list:
+                    data = flush_data(data)
+                    val = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username})), timeout=10).read()
+                    val = val.split("=", 2)[1].split("&", 1)[0]
+                    var_list[p] = val
+                    continue
+                else:
+                    val = var_list[p]
+                    t = "R"
+            else:
+                val = p
+                t = "V"
+            data.append([t, val])
+        data = flush_data(data)
+
+        # Now do linking and loading
+        if link is not None:
+            # Execute linker
+            timeout_val = 10
+            proc2 = execute("link_and_load", [username] + link, wait=False)
+
+            while proc2.returncode is None:
+                time.sleep(0.01)
+                proc2.poll()
+                timeout_val -= 0.01
+                if timeout_val < 0:
+                    kill(proc2)
+                    print("Linking timeout expired!")
+                    return False
+
+        counter = 0
+        for e in expected:
+            print("Expect " + str(e))
+            c = len(e) if isinstance(e, set) else 1
+            for _ in range(c):
+                try:
+                    val = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username})), timeout=15).read()
+                except:
+                    if timeout:
+                        return True
+                    else:
+                        raise
+                val = val.split("=", 2)[2]
+
+                print("Got %s, expect %s" % (val, e))
+                if isinstance(e, set):
+                    assert str(val) in e
+                    if str(val) not in e:
+                        return False
+                else:
+                    assert str(val) == e
+                    if str(val) != e:
+                        return False
+
+        # All passed!
+        return not timeout
+    finally:
+        kill(proc)

+ 212 - 0
interface/HUTN/grammars/actionlanguage.g

@@ -0,0 +1,212 @@
+grammar{
+    start: (include | vardecl | definition | funcdecl | newline)+;
+
+    definition : type_specifier ID ASSIGN atomvalue;
+
+    include: INCLUDE STRVALUE newline+;
+
+    statement: ((vardecl | assignment | return | func_call) newline) | (ifelse | while) | (newline) @Rm;
+
+    vardecl: (GLOBAL)? type_specifier ID;
+
+    assignment
+        :   lvalue ASSIGN expression;
+
+    expression
+        :   binary_operation;
+
+	binary_operation
+	    :   disjunction;
+
+    //lvalue
+    //    :   IDENTIFIER
+    //    |   IDENTIFIER LSQUARE expression RSQUARE;
+
+    disjunction
+        :   (disjunction OR conjunction)
+        |   conjunction;
+
+    conjunction
+        :   (conjunction AND comparison)
+        |   comparison;
+
+    comparison
+        :   (comparison EQ relation)
+        |   (comparison NEQ relation)
+        |   relation;
+
+    relation
+        :   (relation LT sum)
+        |   (relation GT sum)
+        |   (relation LE sum)
+        |   (relation GE sum)
+        |   sum;
+
+    sum
+        :   (sum PLUS term)
+        |   (sum MINUS term)
+        |   term;
+
+    term
+        :   (term STAR factor)
+        |   (term SLASH factor)
+        |   factor;
+
+    factor
+        :   logical_not
+        |   invert_sign
+        |   keep_sign
+        |   primary;
+	logical_not
+	    :   NOT primary;
+	invert_sign
+	    :   MINUS primary;
+	keep_sign
+	    :   PLUS primary;
+
+    primary
+        :   parenthesized
+        |   rvalue
+        |   func_call
+        |   atomvalue;
+
+    parenthesized
+        :   LPAREN expression RPAREN;
+
+    atomvalue: string | integer | float | bool | dictionary | list | type_specifier | actionname | deref;
+
+    deref: QUESTIONMARK ANYTHING?;
+
+    type_specifier: INT | FLOAT | BOOL | STRING | TYPE | ACTION | ELEMENT;
+    actionname: EXCLAMATION (IF_NODE | WHILE_NODE | ASSIGN_NODE | CALL_NODE | BREAK_NODE | CONTINUE_NODE | RETURN_NODE | RESOLVE_NODE | ACCESS_NODE | CONSTANT_NODE | GLOBAL_NODE | DECLARE_NODE | INPUT_NODE | OUTPUT_NODE);
+
+    string: (STRVALUE|LONG_STRVALUE);
+
+    integer: DEC_NUMBER;
+    float: FLOAT_NUMBER;
+
+    rvalue: ID;
+
+    lvalue: ID;
+
+    func_call: rvalue LPAREN (expression (COMMA expression)*)? RPAREN;
+
+    dictionary: LCURLY (dict_item (COMMA dict_item)*)? RCURLY;
+
+    list: LSQUARE (expression (COMMA expression)+)? RSQUARE;
+
+    dict_item: expression COLON expression;
+
+    ifelse: IF expression COLON newline block
+        (indent ELIF expression COLON newline block)#[0]*
+        (indent ELSE COLON newline block)#[0]?;
+
+    while: WHILE expression COLON newline block;
+
+    block: (indent statement)#+;
+
+    func_body: block;
+
+    funcdecl: func_type FUNCTION func_name LPAREN (parameter (COMMA parameter)*)? RPAREN ((COLON newline func_body) | (ASSIGN QUESTIONMARK ANYTHING newline))?;
+
+    func_type: type_specifier | void;
+
+    func_name: ID;
+
+    void: VOID;
+
+    parameter: ID COLON type_specifier;
+
+    return: RETURN expression?;
+
+    indent: TAB;
+
+    bool: TRUE | FALSE;
+
+    newline: COMM* NEWLINE;
+
+    tokens{
+        // TOKENS (written in CAPS)
+        ID: '[a-zA-Z_][a-zA-Z_0-9.]*';
+        ANYTHING: '[a-zA-Z_0-9/.]+';
+        VOID: 'Void';
+        INCLUDE: 'include';
+
+        ELEMENT: 'Element';
+
+        IF_NODE: 'if';
+        WHILE_NODE: 'while';
+        ASSIGN_NODE: 'assign';
+        CALL_NODE: 'call';
+        BREAK_NODE: 'break';
+        CONTINUE_NODE: 'continue';
+        RETURN_NODE: 'return';
+        RESOLVE_NODE: 'resolve';
+        ACCESS_NODE: 'access';
+        CONSTANT_NODE: 'constant';
+        INPUT_NODE: 'input';
+        OUTPUT_NODE: 'output';
+        GLOBAL_NODE: 'global';
+        DECLARE_NODE: 'declare';
+
+        FUNCTION: 'function';
+        RETURN: 'return';
+        GLOBAL: 'global';
+
+        WHILE: 'while';
+        IF: 'if';
+        ELSE: 'else';
+        ELIF: 'elif';
+
+        INT: 'Integer';
+        FLOAT: 'Float';
+        BOOL: 'Boolean';
+        STRING: 'String';
+        TYPE: 'Type';
+        ACTION: 'Action';
+
+        PLUS: '\+';
+        MINUS: '-';
+        STAR: '\*';
+        SLASH: '/';
+        EXCLAMATION: '!';
+        QUESTIONMARK: '\?';
+        COLON: ':';
+        SEMICOLON: ';';
+        ASSIGN: '=';
+        COMMA: ',';
+        LE: '<=';
+        GE: '>=';
+        LT: '<';
+        GT: '>';
+        LPAREN: '\(';
+        RPAREN: '\)';
+        LCURLY: '{';
+        RCURLY: '}';
+        LSQUARE: '\[';
+        RSQUARE: ']';
+        OR: 'or';
+        AND: 'and';
+        NOT: 'not';
+        EQ: '==';
+        NEQ: '!=';
+
+        DEC_NUMBER: '[+-]?(0|[1-9]\d*[lL]?)';
+        POS_DEC_NUMBER: '(0|[1-9]\d*)';
+
+        FLOAT_NUMBER: '[+-]?((\d+\.\d*|\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+)';
+
+        STRVALUE : 'u?r?("(?!"").*?(?<!\\)(\\\\)*?"|\'(?!\'\').*?(?<!\\)(\\\\)*?\')';
+        LONG_STRVALUE : '(?s)u?r?(""".*?(?<!\\)(\\\\)*?"""|\'\'\'.*?(?<!\\)(\\\\)*?\'\'\')';
+
+        NEWLINE: '(\r?\n)+';
+        WS: '[ ]+' @Impl;
+
+        TAB: '\t';
+
+        TRUE: 'True';
+        FALSE: 'False';
+
+        COMM: '[\t]*//[^\n]*';
+    }
+}

+ 34 - 0
interface/HUTN/grammars/modellanguage.g

@@ -0,0 +1,34 @@
+// a simpler action language for the MvK
+
+grammar{
+    start: NEWLINE? modeldecl+;
+    modeldecl: name name? (((LBRA name RBRA)? ASSIGN (name | value)) | (LPAR name COMMA name RPAR))? NEWLINE (indent modeldecl)#*;
+    name: IDENTIFIER;
+    value: DEC_NUMBER | FLOAT_NUMBER | STRVALUE;
+    indent: TAB;
+
+    tokens{
+        // TOKENS (written in CAPS)
+        IDENTIFIER: '[a-zA-Z_][a-zA-Z_0-9]*' @Msg 'Identifier';
+
+        COMMA: ',';
+
+        LPAR: '\(';
+        RPAR: '\)';
+
+        LBRA: '\[';
+        RBRA: '\]';
+
+        ASSIGN: '=';
+
+        DEC_NUMBER: '[+-]?(0|[1-9]\d*[lL]?)';
+        FLOAT_NUMBER: '[+-]?((\d+\.\d*|\.\d+)([eE][-+]?\d+)?|\d+[eE][-+]?\d+)';
+        STRVALUE : 'u?r?("(?!"").*?(?<!\\)(\\\\)*?"|\'(?!\'\').*?(?<!\\)(\\\\)*?\')';
+
+        NEWLINE: '\r?\n+'  @Msg 'Newline';
+        WS: '[ ]+' @Msg 'Whitespace' @Impl;
+        TAB: '\t' @Msg 'Tabspace';
+    }
+}
+
+

+ 0 - 0
interface/HUTN/hutn_compiler/__init__.py


+ 46 - 0
interface/HUTN/hutn_compiler/bootstrap_visitor.py

@@ -0,0 +1,46 @@
+import string
+from primitives_visitor import PrimitivesVisitor
+
+class BootstrapVisitor(PrimitivesVisitor):
+    def __init__(self):
+        PrimitivesVisitor.__init__(self)
+
+    def dump(self):
+        call = self.value("call")
+        access = self.value("access")
+        resolve = self.value("resolve")
+        main = self.value('"__main"')
+        self.dict(resolve, "var", main)
+        self.dict(access, "var", resolve)
+        self.dict(call, "func", access)
+        self.dict(self.last_instruction, "next", call)
+
+        output = []
+        for t, data in self.output:
+            if t == "N":
+                output.append("Node auto_%s()\n" % data)
+            elif t == "V":
+                name, value = data
+                name = name if self.first != name else "initial_IP"
+                output.append("Node auto_%s(%s)\n" % (name, value))
+            elif t == "D":
+                source, value, target = data
+                source = source if self.first != source else "auto_initial_IP"
+                target = target if self.first != target else "auto_initial_IP"
+
+                source = "auto_%s" % source if isinstance(source, int) else source
+                target = "auto_%s" % target if isinstance(target, int) else target
+                # output.append("D %s,%s,%s\n" % (source, value, target))
+                linkname = "%s_%s_%s" % (source, abs(hash(value)), target)
+                output.append("Edge _%s_0(%s, %s)\n" % (linkname, source, target))
+                output.append("Node _%s_2(%s)\n" % (linkname, value))
+                output.append("Edge _%s_1(_%s_0, _%s_2)\n" % (linkname, linkname, linkname))
+            elif t == "E":
+                name, source, target = data
+                source = source if self.first != source else "auto_initial_IP"
+                target = target if self.first != target else "auto_initial_IP"
+                name = "auto_%s" % name if isinstance(name, int) else name
+                source = "auto_%s" % source if isinstance(source, int) else source
+                target = "auto_%s" % target if isinstance(target, int) else target
+                output.append("Edge _%s(_%s, _%s)\n" % (name, source, target))
+        return ''.join(output)

+ 222 - 0
interface/HUTN/hutn_compiler/compiler.py

@@ -0,0 +1,222 @@
+import cPickle as pickle
+import os
+import sys
+
+from grammar_compiler_visitor import GrammarCompilerVisitor
+from hutnparser import Parser, Tree
+from meta_grammar import Grammar
+
+global parsers
+parsers = {}
+
+def read(filename):
+  with open(filename, 'r') as f:
+    return f.read()
+
+def do_parse(inputfile, grammarfile):
+    new_grammar = True
+    picklefile = grammarfile + ".pickle"
+    if grammarfile not in parsers:
+        try:
+            if os.path.getmtime(picklefile) > os.path.getmtime(grammarfile):
+                # Pickle is more recent than grammarfile, so use it
+                grammar = pickle.load(open(picklefile, 'rb'))
+                new_grammar = False
+            else:
+                # Will be catched immediately
+                raise Exception("Pickle is invalid!")
+        except:
+            result = parser = Parser(Grammar(), hide_implicit = True).parse(read(grammarfile))
+            if result['status'] != Parser.Constants.Success:
+                print 'not a valid grammar!'
+                print result
+
+            tree = result['tree']
+            visitor = GrammarCompilerVisitor()
+            structure = visitor.visit(tree)
+            grammar = Grammar()          
+            grammar.rules = structure['rules']
+            grammar.tokens = structure['tokens']        
+            pickle.dump(grammar, open(picklefile, 'wb'), pickle.HIGHEST_PROTOCOL)
+        parsers[grammarfile] = grammar
+    else:
+        new_grammar = False
+        grammar = parsers[grammarfile]
+
+    picklefile = inputfile + ".pickle"
+    try:
+        if new_grammar:
+            # Stop anyway, as the grammar is new
+            raise Exception()
+        if os.path.getmtime(picklefile) > os.path.getmtime(inputfile):
+            # Pickle is more recent than inputfile, so use it
+            result = pickle.load(open(picklefile, 'rb'))
+        else:
+            # Inputfile has changed
+            raise Exception()
+    except:
+        result = Parser(grammar, line_position = True).parse(read(inputfile))
+        if result['status'] != Parser.Constants.Success:
+            print('not a valid input file: %s' % inputfile)
+            print(result)
+        pickle.dump(result, open(picklefile, 'wb'), pickle.HIGHEST_PROTOCOL)
+
+    return result
+
+def find_file(filename, include_paths):
+    import os.path
+    include_paths = ["."] + \
+                    [os.path.abspath(os.path.dirname(working_file))] + \
+                    [os.path.abspath("%s/../includes/" % (os.path.dirname(os.path.abspath(__file__))))] + \
+                    include_paths + \
+                    []
+
+    attempts = []
+    for include in include_paths:
+        testfile = include + os.sep + filename
+        if os.path.isfile(os.path.abspath(testfile)):
+            return os.path.abspath(testfile)
+        else:
+            attempts.append(os.path.abspath(testfile))
+    else:
+        raise Exception("Could not resolve file %s. Tried: %s" % (filename, attempts))
+
+def do_compile(inputfile, grammarfile, compile_visitor = None, compile_visitor2 = None, include_paths = []):
+    import os.path
+    global working_file
+    working_file = os.path.abspath(inputfile)
+
+    result = do_parse(inputfile, grammarfile)
+    error = result["status"] != Parser.Constants.Success
+    if error:
+        print 'not a valid input file!'
+        print '{}:{}: error: {}'.format(result['line'], result['column'],
+                                        result['text'])
+        for r in result['partialresults']:
+            print r
+            if isinstance(r['tree'], Tree):
+                print r['tree'].head, [x.head for x in r['tree'].tail if hasattr(x, 'head')]
+            # print "-"*20+"partial-result"+"-"*20
+            # from prettyprint_visitor import PrintVisitor
+            # pv = PrintVisitor()
+            # pv.visit(r['tree'])
+            # print pv.dump()
+
+    else:
+        for child in result["tree"].tail:
+            child.inputfile = inputfile
+        included = set()
+        while True:
+            for i, v in enumerate(result["tree"].tail):
+                if v.head == "include":
+                    # Expand this node
+                    for j in v.tail:
+                        if j.head == "STRVALUE":
+                            f = str(j.tail[0])[1:-1]
+                            if f in included:
+                                subtree = []
+                            else:
+                                # print find_file(str(j.tail[0])[1:-1], include_paths)
+                                # print do_parse(find_file(str(j.tail[0])[1:-1], include_paths), grammarfile)
+                                name = str(j.tail[0])[1:-1]
+                                subtree = do_parse(find_file(name, include_paths), grammarfile)["tree"].tail
+                                if subtree is None:
+                                    if compile_visitor is None:
+                                        return False
+                                    else:
+                                        return None
+                                for t in subtree:
+                                    t.inputfile = name
+                                included.add(f)
+                            # Found the string value, so break from the inner for ("searching for element")
+                            break
+
+                    # Merge all nodes in
+                    before = result["tree"].tail[:i]
+                    after = result["tree"].tail[i+1:]
+                    result["tree"].tail = before + subtree + after
+                    # Found an include node, but to prevent corruption of the tree, we need to start over again, so break from the outer for loop
+                    break
+            else:
+                # The outer for finally finished, so there were no includes remaining, thus terminate the infinite while loop
+                break
+
+    if compile_visitor is None:
+        return not error
+    else:
+        if error:
+            return None
+        else:
+            try:
+                compile_visitor.visit(result["tree"])
+                if compile_visitor2:
+                    compile_visitor2.visit(result["tree"])
+            except RuntimeError as e:
+                print e.message
+                sys.exit(1)
+
+            if compile_visitor2:
+                return compile_visitor2.dump()
+            else:
+                return compile_visitor.dump()
+
+def main(input_file, grammar_file, mode, args):
+    if mode == "None":
+        visitor = None
+        visitor2 = None
+    elif mode == "PP":
+        from prettyprint_visitor import PrettyPrintVisitor
+        visitor = PrettyPrintVisitor()
+        visitor2 = None
+    elif mode == "P":
+        from prettyprint_visitor import PrintVisitor
+        visitor = PrintVisitor()
+        visitor2 = None
+    elif mode == "S":
+        from semantics_visitor import SemanticsVisitor
+        visitor = SemanticsVisitor()
+        visitor2 = None
+    elif mode == "BS":
+        from semantics_visitor import SemanticsVisitor
+        from bootstrap_visitor import BootstrapVisitor
+        visitor = SemanticsVisitor()
+        visitor2 = BootstrapVisitor()
+    elif mode == "PS":
+        from semantics_visitor import SemanticsVisitor
+        from primitives_visitor import PrimitivesVisitor
+        visitor = SemanticsVisitor()
+        visitor2 = PrimitivesVisitor()
+    elif mode == "PO":
+        from semantics_visitor import SemanticsVisitor
+        from primitives_object_visitor import PrimitivesObjectVisitor
+        visitor = SemanticsVisitor()
+        visitor2 = PrimitivesObjectVisitor(args)
+    elif mode == "CS":
+        from semantics_visitor import SemanticsVisitor
+        from constructors_visitor import ConstructorsVisitor
+        visitor = SemanticsVisitor()
+        visitor2 = ConstructorsVisitor()
+    elif mode == "CO":
+        from semantics_visitor import SemanticsVisitor
+        from constructors_object_visitor import ConstructorsObjectVisitor
+        visitor = SemanticsVisitor()
+        visitor2 = ConstructorsObjectVisitor(args)
+    else:
+        print("Visitor not understood: " + str(mode))
+        sys.exit(1)
+    return do_compile(input_file, grammar_file, visitor, visitor2)
+
+if __name__ == "__main__":
+    if len(sys.argv) <= 2:
+        print("Invocation: ")
+        print("  %s input_file grammar_file [mode]" % sys.argv[0])
+        sys.exit(1)
+    else:
+        value = main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4:])
+        if value is None:
+            sys.exit(1)
+        else:
+            if isinstance(value, list):
+                print '\n'.join([repr(x) for x in value])
+            sys.exit(0)
+

+ 124 - 0
interface/HUTN/hutn_compiler/constructors_object_visitor.py

@@ -0,0 +1,124 @@
+from constructors_visitor import ConstructorsVisitor
+
+import urllib
+import urllib2
+
+timeout = 100
+
+class ConstructorsObjectVisitor(ConstructorsVisitor):
+    def __init__(self, args):
+        ConstructorsVisitor.__init__(self)
+
+        self.username = args[0]
+        self.obj_file = args[1]
+        self.real_file = args[2]
+
+        self.object_symbols = {}
+
+        with open(self.real_file, 'r') as f:
+            import hashlib
+            md5 = hashlib.md5()
+            md5.update(f.read())
+        self.hash_file = md5.hexdigest()
+
+        # Check if file is already compiled (with same hash) in Modelverse
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % self.username, "username": "user_manager"}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": self.username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"is_defined"', "username": self.username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % self.obj_file, "username": self.username}))).read()
+
+        v = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": self.username}))).read()
+        v = v.split("=", 2)[2]
+        if v == "None":
+            # Not defined, so recompile
+            print("[COMPILE] %s" % self.real_file.rsplit("/", 1)[1])
+        else:
+            # Is defined already, so let's compare hashes
+            if v != self.hash_file:
+                print("[COMPILE] %s" % self.real_file.rsplit("/", 1)[1])
+
+                # Remove in Modelverse and recompile
+                urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": self.username}))).read()
+                urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"remove_obj"', "username": self.username}))).read()
+                urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % self.obj_file, "username": self.username}))).read()
+            else:
+                self.visit = lambda i: i
+                self.dump = lambda: True
+                print("[CACHED] %s" % self.real_file.rsplit("/", 1)[1])
+
+    def dump(self):
+        v = ConstructorsVisitor.dump(self)
+
+        import json
+        # Set up interface
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": self.username}))).read()
+
+        # Start uploading the code
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"upload"', "username": self.username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % self.obj_file, "username": self.username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % self.hash_file, "username": self.username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": 'true', "username": self.username}))).read() # Use new interface
+
+        print("Uploading!")
+
+        def flush_data(data):
+            print("Send " + str(data))
+            if data:
+                urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "data": json.dumps(data), "username": self.username})), timeout=timeout).read()
+            return []
+
+        var_list = {}
+        data = []
+        for p in v:
+            if isinstance(p, int):
+                if p not in var_list:
+                    data = flush_data(data)
+                    val = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": self.username})), timeout=timeout).read()
+                    val = val.split("=", 2)[1].split("&", 1)[0]
+                    var_list[p] = val
+                    continue
+                else:
+                    val = var_list[p]
+                    t = "R"
+            else:
+                val = p
+                t = "V"
+            data.append([t, val])
+        data = flush_data(data)
+
+        # Upload symbol table
+        data = []
+        for e, v in self.object_symbols.iteritems():
+            data.append(["V", "true"])
+            data.append(["V", '"%s"' % e])
+            data.append(["V", "true" if v else "false"])
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "data": json.dumps(data), "username": self.username}))).read()
+
+        # Finish the symbol table
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": 'false', "username": self.username}))).read()
+        return True
+
+    def visit_definition(self, tree):
+        for a in tree.get_children("ID"):
+            name = a.get_tail()[0]
+            self.object_symbols[name] = True
+            return ConstructorsVisitor.visit_definition(self, tree)
+
+    def visit_vardecl(self, tree):
+        if len(tree.get_tail()) > 2:
+            for a in tree.get_children("ID"):
+                name = a.get_tail()[0]
+                self.object_symbols.setdefault(name, False)
+                return ConstructorsVisitor.visit_vardecl(self, tree)
+        else:
+            return ConstructorsVisitor.visit_vardecl(self, tree)
+
+    def visit_funcdecl(self, tree):
+        for a in tree.get_children("func_name"):
+            for b in a.get_children("ID"):
+                name = b.get_tail()[0]
+                if tree.get_children("func_body") or tree.get_children("ASSIGN"):
+                    self.object_symbols[name] = True
+                else:
+                    self.object_symbols.setdefault(name, False)
+                return ConstructorsVisitor.visit_funcdecl(self, tree)

+ 296 - 0
interface/HUTN/hutn_compiler/constructors_visitor.py

@@ -0,0 +1,296 @@
+import cPickle as pickle
+from visitor import Visitor
+
+class ConstructorsVisitor(Visitor):
+    def __init__(self):
+        self.constructors = []
+        self.free_id = 0
+
+    def dump(self):
+        return self.constructors
+        # return pickle.dumps(self.constructors, pickle.HIGHEST_PROTOCOL)
+        # return '\n'.join([repr(x) for x in self.constructors])
+
+    def add_constructors(self, *constructors):
+        self.constructors.extend(constructors)
+
+    # a visit_* method for each non-terminal in the grammar
+    def visit_start(self, tree):
+        # declare all functions
+        for child in tree.get_children("funcdecl"):
+            if self.pre_visit_funcdecl(child):
+                self.add_constructors('true')
+
+        tail = tree.get_tail_without(["newline"])
+        # tail = tree.get_children("funcdecl") +\
+        #     tree.get_tail_without(["newline", "funcdecl"])
+        last = tail[-1]
+        for child in tail[:-1]:
+            if child.head == "return":
+                last = child
+                break
+            else:
+                # funcdecl may add no constructors
+                new_constructors_were_added = self.visit(child)
+                if child.head == "func_call":  # pop 'false'
+                    self.constructors.pop()
+                if new_constructors_were_added:
+                    self.add_constructors('true')
+        new_constructors_were_added = self.visit(last)
+        if last.head == "func_call":  # pop 'false'
+            self.constructors.pop()
+        if new_constructors_were_added:
+            if last.head != "return":
+                self.add_constructors('false')
+        elif self.constructors:
+            self.constructors.pop()  # pop 'true'
+            self.add_constructors('false')
+
+    def declare(self, symbol):
+        if symbol.is_global:
+            symbol.node = '"%s"' % symbol.name
+            self.add_constructors('"global"', symbol.node)
+        else:
+            symbol.node = self.free_id
+            self.add_constructors('"declare"', self.free_id)
+            self.free_id += 1
+
+    def visit_vardecl(self, tree):
+        symbol = self.get_symbol(tree)
+        self.declare(symbol)
+        return True
+
+    def visit_assignment(self, tree):
+        self.add_constructors('"assign"')
+        self.visit(tree.get_tail()[0])
+        self.visit(tree.get_tail()[2])
+        return True
+
+    def visit_expression(self, tree):
+        self.visit_children(tree)
+
+    def visit_binary_operation(self, tree):
+        self.visit_children(tree)
+
+    def visit_disjunction(self, tree):
+        self.visit_children(tree)
+
+    def visit_conjunction(self, tree):
+        self.visit_children(tree)
+
+    def visit_comparison(self, tree):
+        self.visit_children(tree)
+
+    def visit_relation(self, tree):
+        self.visit_children(tree)
+
+    def visit_sum(self, tree):
+        self.visit_children(tree)
+
+    def visit_term(self, tree):
+        self.visit_children(tree)
+
+    def visit_factor(self, tree):
+        self.visit_children(tree)
+
+    def visit_primary(self, tree):
+        self.visit_children(tree)
+
+    def visit_parenthesized(self, tree):
+        self.visit_children(tree)
+
+    def visit_atomvalue(self, tree):
+        self.visit_children(tree)
+
+    def visit_type_specifier(self, tree):
+        self.add_constructors('"const"',
+            '{"value": "%s"}' % (tree.get_text()))
+
+    def visit_actionname(self, tree):
+        self.add_constructors('"const"',
+            '{"value": "%s"}' % (tree.get_tail()[1].get_text()))
+
+    def visit_string(self, tree):
+        self.visit_literal(tree)
+
+    # there is no such rule in the grammar, we just avoid code duplicates
+    def visit_literal(self, tree):
+        self.add_constructors('"const"', tree.get_text())
+
+    def visit_integer(self, tree):
+        self.visit_literal(tree)
+
+    def visit_float(self, tree):
+        self.visit_literal(tree)
+
+    def visit_rvalue(self, tree):
+        self.add_constructors('"access"')
+        self.visit_lvalue(tree)
+
+    def visit_lvalue(self, tree):
+        symbol = self.get_symbol(tree)
+        # TODO: split visit_funcdecl in pre_visit_funcdecl and visit_funcdecl
+        if symbol.node is None:
+            raise Exception("Undefined variable: %s" % (symbol.name))
+        self.add_constructors('"resolve"', symbol.node)
+
+    def visit_func_call(self, tree):
+        symbol = self.get_symbol(tree.get_tail()[0])
+        self.add_constructors('"call"')
+        if hasattr(symbol, "pathmv"):
+            self.add_constructors('"deref"', symbol.pathmv)
+        else:
+            self.visit(tree.get_tail()[0])
+        expressions = tree.get_children("expression")
+        self.add_constructors(str(len(expressions)))
+        for expression in expressions:
+            self.visit(expression)
+        self.add_constructors('false')
+        return True
+
+    def visit_input(self, tree):
+        self.add_constructors('"input"')
+        return True
+
+    def visit_output(self, tree):
+        self.add_constructors('"output"')
+        self.visit(tree.get_child("expression"))
+        return True
+
+    def visit_dictionary(self, tree):
+        pass  # TODO: list and dictionary
+
+    def visit_list(self, tree):
+        pass  # TODO: list and dictionary
+
+    def visit_dict_item(self, tree):
+        pass  # TODO: list and dictionary
+
+    def visit_ifelse(self, tree):
+        self.add_constructors('"if"')
+        expressions = tree.get_children("expression")
+        blocks = tree.get_children("block")
+        self.visit(expressions[0])  # condition
+        self.visit(blocks[0])  # then-clause
+
+        for e, b in zip(expressions[1:], blocks[1:]):
+            self.add_constructors('true', '"if"')  # else-if-clause
+            self.visit(e)
+            self.visit(b)
+
+        if len(expressions) != len(blocks):
+            self.add_constructors('true')  # else-clause
+            self.visit(blocks[-1])
+        else:
+            self.add_constructors('false')  # no else_clause
+
+        for i in range(len(expressions)-1):
+            self.add_constructors('false')  # no next
+
+        return True
+
+    def visit_while(self, tree):
+        self.add_constructors('"while"')
+        self.visit(tree.get_child("expression"))
+        self.visit(tree.get_child("block"))
+        return True
+
+    def visit_block(self, tree):
+        tail = tree.get_tail_without(["newline", "indent"])
+        last = tail[-1]
+        for child in tail[:-1]:
+            if child.head == "return":
+                last = child
+                break
+            else:
+                self.visit(child)
+                if child.head == "func_call":  # pop 'false'
+                    self.constructors.pop()
+                self.add_constructors('true')
+        self.visit(last)
+        if last.head == "func_call":  # pop 'false'
+            self.constructors.pop()
+        if last.head != "return":
+            self.add_constructors('false')
+
+    def visit_func_body(self, tree):
+        self.visit_children(tree)
+
+    def pre_visit_funcdecl(self, tree):
+        func_body = tree.get_child("func_body")
+        symbol = self.get_symbol(tree)
+        symbol.node = '"%s"' % symbol.name
+        return False
+
+    def visit_funcdecl(self, tree):
+        func_body = tree.get_child("func_body")
+        symbol = self.get_symbol(tree)
+        if func_body:
+            if symbol.name in ["input", "output"]:
+                return False
+            self.add_constructors('"funcdef"', symbol.node,
+                                  str(len(symbol.params)))
+            for p in tree.get_children("parameter"):
+                self.visit(p)
+            self.visit(func_body)
+            return True
+        elif tree.get_child("ASSIGN"):
+            # TODO: fix funcdecl special case: "X function f(...) = ..."
+            # Note: replicates "Element x; x = ?primiteves/a" behavior
+            # Dangerous: SemanticsVisitor handles it as a function
+            pathmv = tree.get_child("ANYTHING").get_text()
+
+            # pathmv is needed in visit_func_call(self, tree)
+            symbol.pathmv = '"{}"'.format(pathmv)
+
+            self.add_constructors('"global"', symbol.node, '"deref"', symbol.pathmv)
+
+            # reason: "X function f(Y) = Z" adds no constructors
+            return True
+        else:
+            # Just a declaration, so skip
+            return False
+
+    def visit_parameter(self, tree):
+        self.add_constructors(self.free_id)
+        symbol = self.get_symbol(tree)
+        symbol.node = self.free_id
+        self.free_id += 1
+
+    def visit_return(self, tree):
+        self.add_constructors('"return"')
+        if len(tree.get_tail()) > 1:
+            self.add_constructors('true')
+            self.visit(tree.get_tail()[1])
+        else:
+            self.add_constructors('false')
+        return True
+
+    def visit_bool(self, tree):
+        if tree.get_text() == "True":
+            self.add_constructors('"const"', 'true')
+        else:
+            self.add_constructors('"const"', 'false')
+
+    def visit_definition(self, tree):
+        # First declare it
+        symbol = self.get_symbol(tree)
+        symbol.node = '"%s"' % symbol.name
+
+        # Now generate constructors
+        self.add_constructors('"global"', '"%s"' % symbol.name)
+
+        # Determine whether it is just a constant, or a deref
+        atom = tree.get_child("atomvalue")
+        if atom.get_child("deref"):
+            # Deref
+            dest = atom.get_child("deref").get_child("ANYTHING")
+            if dest is None:
+                # Just an empty questionmark!
+                self.add_constructors('"empty"')
+            else:
+                self.add_constructors('"deref"', '"%s"' % dest.get_text())
+        else:
+            # Constant
+            self.visit(atom)
+        return True

+ 43 - 0
interface/HUTN/hutn_compiler/declare_functions_visitor.py

@@ -0,0 +1,43 @@
+import symbol_table as st
+import types_mv
+from visitor import Visitor
+
+
+# Declare the function but do not visit its body
+class DeclareFunctionsVisitor(Visitor):
+    def __init__(self, symbol_table, inputfiles):
+        self.symbol_table = symbol_table
+        self.inputfiles = inputfiles
+
+    def compute_parameter_types(self, tree):
+        parameter_types = []
+        for parameter in tree.get_children('parameter'):
+            type_specifier = parameter.get_tail()[2].get_text()
+            parameter_types.append(types_mv.string_to_type(type_specifier))
+        return parameter_types
+
+    def compute_func_type(self, tree):
+        self.visit(tree.get_tail()[0])
+        func_type = self.get_type(tree.get_tail()[0])
+        return func_type
+
+    def visit_funcdecl(self, tree):
+        func_name = tree.get_tail()[2].get_text()
+        func_type = self.compute_func_type(tree)
+        parameter_types = self.compute_parameter_types(tree)
+        self.set_type(tree, func_type)
+
+        #TODO should check type compatibility if declared multiple times
+        try:
+            s = st.Symbol(func_name, func_type, is_global=True, params=parameter_types)
+            self.symbol_table.add(s)
+        except Exception:
+            if "COLON" in tree.get_tail() or "ASSIGN" in tree.get_tail():
+                raise RuntimeError(
+                    "{}:{}:{}: error: redeclaration of '{}'".format(
+                        self.inputfiles[0], tree.startpos['line'],
+                        tree.startpos['column'], func_name))
+        self.set_symbol(tree, s)
+
+    def visit_func_type(self, tree):
+        self.set_type(tree, types_mv.string_to_type(tree.get_text()))

+ 340 - 0
interface/HUTN/hutn_compiler/grammar_compiler_visitor.py

@@ -0,0 +1,340 @@
+"""
+Author Daniel Riegelhaupt
+Date October 2014
+
+A visitor that takes a tree returned by the parser parsing a grammar
+and returns a structure that the parser can use to parse files written in that grammar
+"""
+from hutnparser import * #we  import the parser for constant, and the Tree Class
+from time import time
+
+def dicToStr(dic):
+    text = ""
+    keys = dic.keys()
+    last = None
+    if len(keys) > 0:
+        last = keys[-1]
+    for key in dic.keys():
+        text +=  "'" + key + "': "
+        val = dic[key]
+        if isinstance(val, dict):
+            text += " { " + dicToStr(val) +" }, \n"
+        else:
+            text += str(val)
+            if key != last:
+                text += ", "
+    return text
+
+
+#some constants rule names
+START_RULE = "start"
+GRAMMAR_RULE = "grammar"
+PROD_RULE = "production_rule"
+
+RULE_DEF = "rule_definition"
+RULE_NAME = "rule_name"
+RULE_RHS = "rule_right_hand_side"
+
+TOKEN_DEF = "token_definition"
+TOKEN_COLLECTION = "token_collection"
+TOKEN_SUB_COLLECTION = "token_sub_collection"
+TOKEN_NAME= "token_name"
+TOKEN_VALUE = "token_value"
+
+KEYWORD_TYPE = "keywords"
+MESSAGE = "message"
+
+MODIFIER = "modifier"
+IMPL_MOD = "IMPLICIT_MOD" #token name  not a rule name
+REMOVE = "remove"
+
+#for rhs rules
+CARD_RULE = "cardinality"
+MINUS= "MINUS" #token name  not a rule name
+INT = "INT" #token name  not a rule name
+
+OPER = "OPER"
+OR = "OR"
+LPAR = "LPAR"
+RPAR = "RPAR"
+
+#parser constants
+TOKEN_TYPE = Parser.Constants.Token
+PROD_TYPE=  Parser.Constants.Production
+
+class Visitor(object):
+    """
+    The way the data structure is: a token is a tree with a tail containing a single string
+    so it isn't enough to just check for isInstance
+    """
+    def isTree(self, item):
+        ret = False
+        if isinstance(item, Tree):
+            if len(item.tail) > 1:
+                ret = True
+            elif len(item.tail) == 1 and isinstance(item.tail[0], Tree):
+                ret = True
+        return ret
+
+    def isToken(self,item):
+        ret = False
+        if isinstance(item, Tree):
+            if len(item.tail) == 1 and isinstance(item.tail[0], basestring):
+                ret = True
+        return ret
+
+    def getTokenValue(self, item):
+        #in a rule like Place : place_name ....,
+        # place_name : LOWER_LETTER
+        #and item is place_name than the value is at the bottom of place_name -> LOWER_LETTER -> value
+        #USE ONLY WHEN SURE YOU ARE EXPECTING A TOKEN VALUE
+        while item and isinstance(item, Tree):
+            item = item.tail[0]
+        return str(item)
+
+
+class GrammarCompilerVisitor(Visitor):
+    def __init__(self):
+        self.tokens = {}
+        self.rules = {}
+        self.keywords = {}
+        self.implicit = []
+
+    def visit(self, tree):
+        if self.isTree(tree):
+            if tree.head == START_RULE:
+                for item in tree.tail:
+                    if self.isTree(item) and item.head == GRAMMAR_RULE:
+                        self.visitGrammar(item)
+                    #elif self.isTree(item, Tree) and item.head == MAPPER_RULE:
+                    #    self.visitMapper(item)
+                    #    TODO or maybe in a complete separate visitor depending on how complex this one gets
+
+        self.addImplicit()
+        #print "rules: "
+        #print dicToStr(self.rules)
+
+        return {'rules': self.rules, 'tokens': self.tokens}
+
+    def visitGrammar(self,tree):
+        if self.isTree(tree):
+            for child in tree.tail:
+                if self.isTree(child):
+                    rule = child.head
+                    if rule == PROD_RULE: #a grammar consists of prod rules and a prod rule can be a rule or token
+                        self.visitGrammar(child)
+                    elif rule == RULE_DEF: #top level rule definition
+                        self.visitRule(child)
+                    elif rule == TOKEN_COLLECTION: #part of th grammar where tokens are defined as a def or collection
+                        self.visitTokens(child)
+                    else:
+                        print 'Encountered unexpected rule type in grammar rule. type: ', rule
+
+    def visitRule(self,tree):
+        if self.isTree(tree):
+            name = ''
+            body = ''
+            msg = ''
+            rm = False
+            for child in tree.tail:
+                if self.isTree(child):
+                    rule = child.head
+                    if rule == RULE_NAME:
+                       name = self.getTokenValue(child)
+                       # print name
+                    elif rule == RULE_RHS:
+                        body = self.createRHS(child)
+                    elif rule == MESSAGE: #part of th grammar where tokens are defined as a def or collection
+                        #TODO this will not work for the moment due to having an extra parent
+                        #the child  0 is @Msg or Message
+                        #child 1 is a token of type REGEXP and his tail contains the value
+                        msg = self.getTokenValue(child.tail[1])
+                    elif rule == REMOVE:
+                        rm = True
+                    else:
+                        print 'Encountered unexpected rule type in rule definition. type: ', rule
+
+            if name and body:
+                mesg = msg
+                if not mesg: #if there was no message
+                    msg = name #than the message is the name of the rule
+                self.addRule(name, body, mesg, rm)
+
+    def createRHS(self, tree):
+        body, boolean = self.innerRHS(tree)
+        return body
+
+    def innerRHS(self, tree):
+        """
+        a | b| c in the grammar wil return  will return
+        a tree that if simply traverse directly wil returned the structure [ | , a [ |, b, c]]
+        we want it to return [|a,b,c]
+        hence the unpacking
+
+        on the other hand if the user explicitly puts a | ( b| c)
+        we do not allow unpacking   so as to return the structure the user expects
+        (even though they are equivalent and the above is simpler )
+        hence a bool that says we are not allowed to unpack
+        """
+        #reqUnpack = False #expecting to unpack
+        allowUnpack = True #allow unpacking in upperlevel of recursion
+        operator = '.' #we always assume it is a sequence we can change it later if we are wrong
+        rhs = []
+        for item in tree.tail:
+            head = item.head
+            if self.isTree(item):
+                if head == TOKEN_NAME: # a reference to a token
+                    tok =  '$' + self.getTokenValue(item)
+                    rhs.append(tok)
+
+                elif head == TOKEN_VALUE: #an anonymous token, written directly in the rule
+                    tok = self.getTokenValue(item)
+                    rhs.append(tok[1:-1])
+
+                elif head == RULE_NAME: #a reference to a rule
+                    rule =  '@' + self.getTokenValue(item)
+                    rhs.append(rule)
+
+                elif head == CARD_RULE: #there is a cardinality operator
+                    #TODO for the moment this has the same bug as message: instead of being at the same level as other child nodes
+                    #this has an extra parent with the same name as its true parent namel rule_right_hand_side
+                    #(rule_definition for message)
+
+                    allowUnpack = False
+                    operator = '#'
+                    extra = '('
+                    for child in item.tail:
+                        if child.head == MINUS:
+                            extra += '-'
+                        if child.head == INT:
+                            extra += self.getTokenValue(child) + ')'
+                            operator += extra
+
+                elif head == RULE_RHS: # another rhs rule
+                    r, u = self.innerRHS(item)
+                    if u == True:
+                        #if operator == '|':
+                        #    print "INNER RULE: | begin replaced by: " , r[0]
+                        #operator = r[0]
+                        if r[0] == '|' and operator == '.':
+                            operator = '|'
+                        for item in r[1:]:
+                            rhs.append(item)
+
+                    else:
+                        rhs.append(r)
+                else:
+                    print 'Encountered unexpected rule type in tree RHS with head: ', item.head
+            elif self.isToken(item):
+                #print "TOKEN INNER in rule:",  tree.head, "with name", item.head, " value", self.getTokenValue(item)
+                head = item.head
+                if head == OPER:
+                    operator = self.getTokenValue(item)
+                    allowUnpack = False
+                elif head == OR:
+                    operator = '|'
+                    #reqUnpack = True
+                elif head == LPAR:
+                    allowUnpack = False #whatever is here belongs togheter and can't be unpacked at a higher level
+                elif head == RPAR:
+                    pass #the case is here because it is legal but doesn't require any other action than LPAR
+                else:
+                    print 'Encountered unexpected Token in RHS of kind: ', head
+
+        if operator == '.' or operator == '|':
+            rhs = [operator] + rhs
+        elif not operator.startswith('#'): #so * + or ?
+            if len(rhs) == 1:
+                rhs = [operator] + rhs
+            else:
+                rhs = [operator] + ['.' , rhs ]
+        else:
+            #TODO uncomment this when bug about parent level is fixed for card (and message)
+            zero = str(rhs[0])
+            if zero.startswith('@') or zero.startswith('$'):
+                zero = zero[1:]
+            rhs[0] = operator + zero
+
+        return rhs , allowUnpack
+
+    def addImplicit(self):
+        if self.implicit and self.rules.has_key('start'):
+
+            t = str(time())
+            t = t.replace('.','')[:-5]
+            name = 'implicit_autogenerated_' + t
+            #name + random number to avoid any conflicts with possible names
+
+            impl=  ['|'] + self.implicit
+            body = [ '*', impl ]
+            msg = "Automatically generated 'Implict' rule"
+
+            #we add it to the rules
+            self.addRule(name, body, msg)
+            self.rules['start']['interleave'] = ['?', '@' + name]
+
+
+    def visitTokens(self,tree):
+        if self.isTree(tree):
+            for child in tree.tail:
+                if self.isTree(child):
+                    rule = child.head
+                    if rule == TOKEN_DEF:
+                        self.fillTokenInfo(child)
+                    elif rule == TOKEN_SUB_COLLECTION:
+                        #a collection is 0 type 1: 2 name 3 {  4 and further token_defs last }
+                        colType  = self.getTokenValue(child.tail[0])
+                        colName = self.getTokenValue(child.tail[2])
+                        for item in child.tail[4:]:
+                            if self.isTree(item) and item.head == TOKEN_DEF:
+                                self.fillTokenInfo(item,colType, colName)
+                    else: #token_collection_content is the  parent of both token def and token sub collection
+                        self.visitTokens(child)
+
+    def fillTokenInfo(self,tree, colType = None, colName = ''):
+        name = ''
+        val = ''
+        msg = ''
+        rm = False
+        for item in tree.tail:
+            if self.isTree(item):
+                head = item.head
+                if head == TOKEN_NAME:
+                    #roken name contains a child of type token uppercase and this child contains the actual value
+                    name =  self.getTokenValue(item)
+                elif head == TOKEN_VALUE:
+                    val = self.getTokenValue(item)
+                elif head == MESSAGE:
+                    #the child  0 is @Msg or Message
+                    #child 1 is a token of type REGEXP and his tail contains the value
+                    msg = self.getTokenValue(item.tail[1])
+                elif head == MODIFIER:
+                    #the tail is the token, the head gives us the name we don't need the actual value
+                    #especially since the actual value might change
+                    if item.tail[0].head == IMPL_MOD:
+                        self.implicit.append( '$' + name)
+                    #else:
+                        #pass
+                        #TODO if there are multiple modifers do something
+                elif head == REMOVE:
+                    rm = True
+            if name and val:
+                mesg = msg
+                if not mesg: #if there was no message
+                    msg = val #than the message is the value of the token
+                self.addToken(name, val, mesg, rm)
+
+    def addToken(self, name, value, msg, hidden = False):
+        msg = str(msg[1:-1])
+        value = str(value[1:-1])
+        val = {'type': TOKEN_TYPE, 'reg': value, 'errortext': msg }
+        if (hidden == True):
+            val['hidden'] = True
+        self.tokens[name] = val
+
+    def addRule(self, name, rhs, msg, hidden = False):
+        msg = str(msg[1:-1])
+        val = {'type': PROD_TYPE, 'body': rhs, 'errortext': msg }
+        if (hidden == True):
+            val['hidden'] = True
+        self.rules[name] = val

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

@@ -0,0 +1,976 @@
+"""
+Author: Bruno Barroca
+Date: October 2014
+Description: A top down parser
+
+Modifications by Daniel Riegelhaupt:
+*removed test input
+*changed pos to startpos because in my humble opinion it makes more sense to have a tupple (startpos, endpos) than (pos, endpos)
+*aded parameters to init: tab_size, line_position, hide_implicit
+ - see init comments for more info on all otions
+ - line_postion will change startpos and end Pos to instance of class Postion. (changed december 2014)
+*Added anonymous terminals: tokens do not have to be defined as tokens but can be typed directly in rules
+*changed interleave function to be deep, and start on START
+*changed position returned in tree to be relative to line numbers instead of the absolute one
+ - Did the same for partialresults returned on syntax error change this is error results too
+ - TODO check efficiency on the previous point checking the whole text for every position might be slow
+*Changed usage , instead of Parser(input, grammar).pars() it is now Parser(grammar).parse(input)
+ - Added a self.reset() method for fields that need to be initializes again when parsing a new input
+*Changed findFailure and generateErrorReports:
+ * i need the the rule/token name as well not only the error text
+ * hidden  elements (like for example comments and newline ) are not included in error reports if hide_implicit is set to true
+ * same for the interleave rule
+"""
+
+import re
+
+from copy import deepcopy 
+
+from position import Position
+
+class Tree(object):
+    def __init__(self, head, tail, startpos, endpos):
+        self.head = head
+        self.tail = tail
+        self.startpos = startpos
+        self.endpos = endpos
+        self._tail = None
+        self.inputfile = ""
+        # IMPORTANT: self.replaced: replace_child defines self.replaced
+
+    def is_rule(self):
+        return self.head.islower()
+
+    def is_token(self):
+        return not self.is_rule()
+
+    def get_tail(self):
+        if self.is_rule():
+            if not self._tail:
+                self._tail = [t for t in self.get_raw_tail()
+                              if not t.head.startswith("implicit_autogenerated_")]
+            return self._tail
+        else:
+            return self.get_raw_tail()
+
+    def get_raw_tail(self):
+        return self.tail
+
+    def get_text(self, with_implicit=False):
+        parts = []
+
+        if with_implicit:
+            tail = Tree.get_raw_tail
+        else:
+            tail = Tree.get_tail
+
+        def post_order(tree):
+            for child in tail(tree):
+                if hasattr(child, "replaced"):
+                    child = child.replaced
+                if isinstance(child, Tree):
+                    post_order(child)
+                else:
+                    parts.append(child)
+
+        post_order(self)
+
+        return ''.join(parts)
+
+    def get_child(self, name):
+        for child in self.get_tail():
+            if child.head == name:
+                return child
+        return None
+
+    def get_children(self, name):
+        children = []
+        for child in self.get_tail():
+            if child.head == name:
+                children.append(child)
+        return children
+
+    def replace_child(self, old_child, new_child):
+        new_child.replaced = old_child
+
+        i = self.get_raw_tail().index(old_child)
+        self.get_raw_tail()[i] = new_child
+
+        i = self.get_tail().index(old_child)
+        self.get_tail()[i] = new_child
+
+    def get_tail_without(self, names):
+        if self.is_rule():
+            return [t for t in self.get_tail() if not t.head in names]
+        else:
+            return self.get_raw_tail()
+
+    def __str__(self):
+        return "(%s, %s) [%s]" % (
+            self.head, str((self.startpos, self.endpos)),
+            ", ".join([str(i) for i in self.get_raw_tail()]))
+
+
+class Parser(object):
+    class Constants(object):
+        Token = 'token'
+        Production = 'prod'
+        Success = 'success'
+        Failure = 'failure'
+
+    class LR(object):
+        def __init__(self, seed, rulename, head, nextlr):
+            self.seed = seed
+            self.rule = rulename
+            self.head = head
+            self.next = nextlr
+
+        def copy(self):
+            return Parser.LR(self.seed, self.rule, self.head, self.next)
+
+    class Head(object):
+        def __init__(self, rulename, involved, evaluation):
+            self.rule = rulename
+            self.involved = involved
+            self.evaluation = evaluation
+
+    def __init__(self, grammar, **options):
+        """
+        creates a Parser for the given grammar
+        :param grammar: An instance of the Grammar class
+        :param options: the following options are supported:
+            tab_size: default 1. sets the character size of a tab character
+            hide_implicit: default False. when true implicit tokens are hidden from the returned parse tree and error message.
+                           Note that this this option will not override rules or tokens where the hidden variable has already been set manually in the Grammar class
+            line_position: default False. when true we use line, column Position object instead of absolute position integer in the parse tree for startpos and endpos
+        """
+        #changed by Daniel: members that need to be initialized each time parse is a called have been put in def reset()
+        #that method is called when the parse() method is called
+        self.rules = deepcopy(grammar.rules)
+        self.tokens = deepcopy(grammar.tokens)
+        self.implicitList = [] #added by Daniel, set in hideImplict so that we can review the implicit list in case of error messages
+        self.implictRuleName = ""
+
+        #options Added by Daniel
+        self.tabsize = int(options.pop('tab_size', 1)) #the character size of a tab
+        self.hideImplicit = bool(options.pop('hide_implicit', False))
+        #whether to hide implicit tokens and rules from the returned parse tree
+        #Important note: this option will not override rules or tokens where the hidden variable has already been set manually
+        self.linePosition = bool(options.pop('line_position', False))
+        #if true the position of the returned parse tree will consist of a line and a column instead of the position in the string array
+
+        #preprocess must happen after options, (after hideImplicit has been set)
+        self.preprocess()
+
+    def reset(self):
+        self.input = ""
+        self.memotable = {}
+        self.failure = {}
+        self.lrstack = None
+        self.heads = {}
+        self.countcard = {}
+
+
+    def preprocess(self):
+        #for elem in self.rules.keys(): #Changed by Daniel: we only check start because it's global
+        elem = 'start'
+        if elem in self.rules.keys():
+            if ('interleave' in self.rules[elem]):
+                ilist = self.rules[elem]['interleave']
+                self.setHideImplicit(ilist, self.hideImplicit)
+                self.interleave(self.rules[elem], ilist)
+
+    def setHideImplicit(self, ilist, bool= False):
+        if ilist:
+            #ilist = ['?', '@rulename']
+            rulename= ilist[1][1:]
+            self.implictRuleName = rulename #used to hide later error reports later
+            self.rules[rulename]['hidden'] = bool
+            if rulename in self.rules:
+                body = self.rules[rulename]['body']
+                #body = [*, [| ,,,,]]
+                elems= body[1][1:]
+                self.implicitList = elems
+                for elem in elems:
+                    l = None
+                    error = ''
+                    if elem[0] == '@':
+                        l = self.rules
+                        error =  ' rule not found in grammar rules.'
+                    elif elem[0]== '$':
+                        l = self.tokens
+                        error =  ' token not found in grammar rules.'
+                    #else: in this case it is an anonymous token,
+
+                    if l:
+                        name = elem[1:]
+                        if name in l:
+                            if not l[name].has_key('hidden'):
+                                #this method will not override anything the user has explicitly specified in the structure
+                                #if there is already a hidden value there it will be kept even if it is not the same one
+                                #an examples use case is whitespaces vs comments:
+                                #both can appear anywhere in the text and so are implicit in the grammar.
+                                #however we dont want spaces in the tree but we do want the comments
+                                l[name]['hidden'] = bool
+                        else:
+                             raise Exception(name + error)
+                    #else: Anon token can't be ignored for the  moment unless we create an ignore list for it or something like that.
+
+            else:
+                raise Exception(rulename + ' rule not found in grammar rules.')
+
+
+    def interleave(self, elem, ilist):
+        #quick and simple interleaving method, will probably contain double interleaving
+        #but this is as simple as i could make it without taking into account each and every case
+        def quickInterLeave(lst, inter):
+            newL = []
+            newL.append(lst[0])
+            isSeq = self.isSequence(lst[0])
+            for item in lst[1:]:
+                if (isinstance(item, list)):#a sublist
+                    newL.append(quickInterLeave(item,inter))
+                else:
+                    if(item[0] == '@'): #rule
+                        rulename = item [1:]
+                        if rulename in self.rules:
+                            rule = self.rules[rulename]
+                            if not rule.has_key('visited') or rule['visited'] == False:
+                                self.interleave(rule, inter)
+                        else:
+                            raise Exception(rulename + ' rule not found in grammar rules.')
+                    """
+                    Else:
+                        pass
+                    in this case it is a token or anon token we dont need to do anything special,
+                    just add it to the list interleaved
+                    """
+
+                    if isSeq: # no need to complicate the data structure if the list is a sequence
+                        if not newL[-1] == inter:
+                            newL.append(inter)
+                        newL.append(item)
+                        newL.append(inter)
+                    else:
+                        newL.append(['.', inter,item ,inter])
+
+                        """
+                        This way in case the list is not a sequence this doesnt change the meaning of the list:
+                        example: t1, t2 are tokens, i is an optional whitespace being intereleaved
+                        [., t1, t2] ->  [., i ,t1, i, t2]
+                        the meaning stays the same:
+                        t1 and t2 both have ot be found for the rule to apply regardless of the ws
+                        [|, t1, t2] ->  [|, i ,t1, i, t2]
+                        the meaning changed: if i is encountered the or is satisfied:
+                        so instead we do ->  [|, [., i ,t1, i,], [., i ,t2, i,]]
+
+                        note that while inter has been added to the data stricture 4 times it will only match
+                        for one option so it is not really duplicate.
+                        another way of writing this can be [., inter [|, t1, t2], inter ] but this is easier said than
+                        done especially for big (complex) data structures
+                        """
+            return newL
+
+        #the first thing we do is say that the item has been visited this will avoid infinite loop due to recursion
+        elem['visited'] = True
+        if (not 'body' in elem):
+            return
+
+        ls = elem['body']
+        newbody = quickInterLeave(ls,ilist)
+        elem['body'] = newbody
+
+    def parse(self, text):
+        self.reset() #Changed by Daniel receive text as param. instead of once at init so first we reset the fields
+        self.input = text
+        results = self.applyrule('@start', 0)
+        if (results == [] or results[0]['endpos'] < len(self.input)):
+            result = self.generateErrorReport()
+            for elem in result['partialresults']: #Added by Daniel there was no post processing on partial results. I need it
+                if elem['tree']: #with partial results the tree can be None
+                    elem['tree'] = IgnorePostProcessor(self.rules, self.tokens).visit(elem['tree'])
+                    if self.linePosition:
+                        # elem['tree'].startpos = 0
+                        # elem['tree'].endpos = 0
+                        elem['tree'] = Parser.PositionPostProcessor(self.convertToLineColumn).visit(elem['tree']) #Added by Daniel
+        else:
+            result = results[0]
+            result.update({'status': Parser.Constants.Success})
+            if result['tree'].head != 'start':
+                result['tree'] = Tree('start', [result['tree']], result['tree'].startpos, result['tree'].endpos)
+            result['tree'] = IgnorePostProcessor(self.rules, self.tokens).visit(result['tree'])
+            if self.linePosition: #Added by Daniel
+                result['tree'] = Parser.PositionPostProcessor(self.convertToLineColumn).visit(result['tree'])
+        return result
+
+    def convertToLineColumn(self, pos):
+        line = 1
+        column = 0
+        l = len(self.input)
+        for i in range(0, l):
+            if (i > pos):
+                break
+            if self.input[i] == '\n':
+                line += 1
+                column = 0
+            elif self.input[i] == '\t':
+                column += self.tabsize #changed by Daniel: this used to be 4
+            else:
+                column += 1
+        if pos >= l: #the end of the text
+            """
+            added by Daniel: needed for the case of the last word/character.
+            Assume a text on one word 'foo'
+            in absolute position the tree says word is from 1 to 4 (as always 'to' means not included)
+            in this method we only count until the range so we would return line 1 col 1 to line 1 col 3
+            but we need col 4
+            we could just says pos == l but i think its better to say any position bigger than the text is simply the end of the text
+            """
+            column += 1
+        return {'line': line, 'column': column}
+
+    def findlargerresultat(self, pos):
+        endpos = pos
+        result = None
+        for key in self.memotable.keys():
+            elem = self.memotable[key]
+            if (elem == []):
+                continue
+            if (elem[0]['startpos'] == pos and endpos < elem[0]['endpos']):
+                endpos = elem[0]['endpos']
+                result = elem[0]
+        return result
+
+    def generateErrorReport(self):
+        # consult the memotable and collect contiguities until endpos
+        endpos = len(self.input) - 1
+        pos = 0
+        elems = []
+        while pos <= endpos:
+            elem = self.findlargerresultat(pos)
+            if (not elem or (elem and elem['endpos'] == pos)):
+                break
+            pos = elem['endpos']
+            elems.append(elem)
+        if (pos <= endpos):
+            elems.append({'tree': None, 'startpos': pos, 'endpos': endpos})
+
+        elem = self.getFirstBiggestSpan(elems)
+
+        if elem is None:
+            return {'status': Parser.Constants.Failure, 'line': 0, 'column': 0, 'text': "Empty input file", 'partialresults': [], 'grammarelements': None}
+        reasons = self.findFailure(elem['startpos'], elem['endpos'])
+        if (reasons == []):
+            pos -= 1
+        else:
+            pos = reasons[0]['startpos']
+        read = self.input[pos:pos + 1]
+        linecolumn = self.convertToLineColumn(pos)
+        message = 'Syntax error at line ' + str(linecolumn['line']) + ' and column ' + str(linecolumn['column']) + '. '
+        keys = []
+        if (not reasons == []):
+            first = True
+            for reason in reasons:
+                if (first):
+                    message += 'Expected ' + reason['text']
+                    first = False
+                else:
+                    message += ' or ' + reason['text']
+                keys.append(reason['key'])
+            message += '. Instead read: ' + repr(read) + '.'
+        else:
+            message += 'Read: \'' + read + '\'.'
+
+        return {'status': Parser.Constants.Failure, 'line': linecolumn['line'], 'column': linecolumn['column'],
+                'text': message, 'partialresults': elems, 'grammarelements': keys}
+
+    def getFirstBiggestSpan(self, elems):
+        biggestspan = 0
+        result = None
+        for elem in elems:
+            span = elem['endpos'] - elem['startpos']
+            if (biggestspan < span):
+                result = elem
+                span = biggestspan
+        return result
+
+    def findFailure(self, pos, endpos):
+        posreasons = []
+        endposreasons = []
+
+        #changed by Daniel:
+        #* i need the key as well for autocomplete so in stead of appending elem i return a new dictionary with elem and the key inside
+        #* checks both condition for posreasons and endposreasons in one for loop instead of 2
+        #* do not cosider keys that are hidden
+
+
+        for key in self.failure.keys():
+            #keys are given starting either with $ for tokens or @ for rules
+            #howver with the the given metagrammar Tokens are all caps and rules are all in small letters so there cant be an overlapp
+            #and we can safely test both
+            if self.hideImplicit and\
+               (('$' + key in self.implicitList) or ('@' + key in self.implicitList) or (key == self.implictRuleName)):
+                continue
+            else:
+                elem = self.failure[key]
+                if (elem['startpos'] == pos and not elem['text'] == ''):
+                    posreasons.append({'key': key, 'startpos': elem['startpos'] , 'text': elem['text'] })
+
+                if (elem['startpos'] == endpos and not elem['text'] == ''):
+                    endposreasons.append({'key': key, 'startpos': elem['startpos'] , 'text': elem['text'] })
+
+        if (len(endposreasons) < len(posreasons)):
+            return posreasons
+        else:
+            return endposreasons
+
+    def setupLR(self, rule, elem):
+        if (elem.head == None):
+            elem.head = Parser.Head(rule, [], [])
+
+        s = self.lrstack
+        while s and not s.rule == elem.head.rule:
+            s.head = elem.head
+            if (not s.rule in elem.head.involved):
+                elem.head.involved.append(s.rule)
+            s = s.next
+
+    def recall(self, rule, j):
+        newresults = []
+        if ((rule, j) in self.memotable):
+            newresults = self.memotable[(rule, j)]
+
+        h = None
+        if (j in self.heads):
+            h = self.heads[j]
+        if (not h):
+            return newresults
+
+        if (newresults == [] and not rule in (h.involved + [h.rule])):
+            return []  # [{'tree': [], 'startpos': j, 'endpos': j}]
+
+        if (rule in h.evaluation):
+            h.evaluation.remove(rule)
+            newresults = self.eval(rule, j)
+            self.memotable.update({(rule, j): newresults})
+
+        return newresults
+
+    def applyrule(self, rule, j):
+        overallresults = []
+
+        newresults = self.recall(rule, j)
+        if (not newresults == []):
+            memoresults = []
+            for elem in newresults:
+                if (isinstance(elem['tree'], Parser.LR)):
+                    self.setupLR(rule, elem['tree'])
+                    memoresults += elem['tree'].seed
+                else:
+                    overallresults.append(elem)
+            if (not memoresults == []):
+                self.memotable.update({(rule, j): memoresults})
+                return memoresults
+            return overallresults
+        else:
+            #lr = Parser.LR([], rule, None, deepcopy(self.lrstack))
+            lr = Parser.LR([], rule, None, None if not self.lrstack else self.lrstack.copy())
+            self.lrstack = lr
+            self.memotable.update({(rule, j): [{'tree': lr, 'startpos': j, 'endpos': j}]})
+
+            newresults = self.eval(rule, j)
+            self.lrstack = self.lrstack.next
+
+            memoresults = []
+            if ((rule, j) in self.memotable):
+                memoresults = self.memotable[(rule, j)]
+            for melem in memoresults:
+                if (isinstance(melem['tree'], Parser.LR) and melem['tree'].head):
+                    melem['tree'].seed = newresults
+                    r = self.lr_answer(rule, j, melem)
+                    if (not r == []):
+                        overallresults += r
+            if (overallresults != []):  # prefer grown results
+                return overallresults
+
+            self.memotable.update({(rule, j): newresults})
+            return newresults
+
+    def lr_answer(self, rule, pos, melem):
+        h = melem['tree'].head
+        if (not h.rule == rule):
+            return melem['tree'].seed
+        else:
+            melems = melem['tree'].seed
+            result = []
+            for melem_i in melems:
+                if (not melem_i['tree'] == None):
+                    result.append(melem_i)
+            if (result == []):
+                return []
+            else:
+                newresult = []
+                for melem_i in result:
+                    newresult.append(self.growLR(rule, pos, melem_i, h))
+                return newresult
+
+    def growLR(self, rule, pos, melem, head=None):
+        self.heads.update({pos: head})
+        while (True):
+            overallresults = []
+            head.evaluation = deepcopy(head.involved)
+            newresults = self.eval(rule, pos)
+            for elem in newresults:
+                if (elem['endpos'] > melem['endpos']):
+                    melem = elem
+                    overallresults.append(elem)
+            if (overallresults == []):
+                self.heads.update({pos: None})
+                return melem
+            self.memotable.update({(rule, pos): overallresults})
+
+    def eval(self, rulename, j):
+        # Returns [{'tree':Tree(head=rulename, tail=[...], startpos=j, endpos=x), 'startpos':j, 'endpos':x}]
+        # Raises Exception if there is no such token/rule
+        if (rulename[0] == '@'):
+            rulename = rulename[1:]
+            if (not rulename in self.rules):
+                raise Exception(rulename + ' rule not found in grammar rules.')
+            rule = self.rules[rulename]
+        elif (rulename[0] == '$'):
+            rulename = rulename[1:]
+            if (not rulename in self.tokens):
+                raise Exception(rulename + ' token not found in grammar tokens.')
+            rule = self.tokens[rulename]
+        else:
+            # raise Exception('Plain terminals not allowed inside grammar rules: ' + str(rulename))
+            # we create an anonymous token rule
+            # we can write whatever we want as fake type as long as it is not equal to the type of the prodcution rule
+            # or to that of the token
+            rule = {'type': 'anonymous_token'}
+
+        if (self.isType(rule, Parser.Constants.Production)):
+            newresults = []
+            results = self.eval_body(rulename, rule['body'], j)
+            for r in results:
+                if (r['tree']):
+                    head = r['tree'].head
+                    if(head == '*' or head == '+' or head == '?' or head == '|' or head == '.'):
+                        newr = {'tree': Tree(rulename, [r['tree']], r['startpos'], r['endpos']), 'startpos': r['startpos'],
+                         'endpos': r['endpos']}
+                        r = newr
+                newresults.append(r)
+        elif (self.isType(rule, Parser.Constants.Token)):
+            newresults = self.term(rulename, j)
+        else: ##Changed by Daniel: if not a production rule or defined token we try an anonymous token:
+            newresults = self.anonTerm(rulename, j)
+        return newresults
+
+    def eval_body(self, rulename, ls, j):
+        # Delegates the task to sub-functions: alt, seq, opt, many, more, card
+        # Returns
+        # Raises Exception if the first element in the body is not in {'|', '.', '?', '*', '+', '#'}
+        if (self.isAlternative(ls[0])):
+            return self.alt(rulename, ls[1:], j)
+        elif (self.isSequence(ls[0])):
+            return self.seq(rulename, ls[1:], j)
+        elif (self.isOptional(ls[0])):
+            return self.opt(rulename, ls[1:], j)
+        elif (self.isMany(ls[0])):
+            return self.many(rulename, ls[1:], j)
+        elif (self.isMore(ls[0])):
+            return self.more(rulename, ls[1:], j)
+        elif (self.isCard(ls[0])):
+            return self.card(rulename, ls[0][1:], ls[1:], j)
+        raise Exception('Unrecognized grammar expression: ' + str(ls[0]))
+
+    def isSequence(self, operator):
+        return operator == '.'
+
+    def isAlternative(self, operator):
+        return operator == '|'
+
+    def isMany(self, operator):
+        return operator == '*'
+
+    def isCard(self, operator):
+        return operator.startswith('#')
+
+    def isMore(self, operator):
+        return operator == '+'
+
+    def isOptional(self, operator):
+        return operator == '?'
+
+    def isType(self, rule, oftype):
+        if (rule['type'] == oftype):
+            return True
+
+    def term(self, rulename, j):
+        if (j >= len(self.input)):
+            errortext = ''
+            if (rulename in self.tokens and 'errortext' in self.tokens[rulename]):
+                errortext = self.tokens[rulename]['errortext']
+            self.failure.update({rulename: {'startpos': j, 'text': errortext}})
+            return []
+
+        rule = self.tokens[rulename]
+        mobj = re.match(rule['reg'], self.input[j:])
+        #Changed by daniel instead of re.match(reg) did re.match(re.compile(reg).patern)
+        #this is to avoid problems with \ before i did this i had the match the character \ by doing [\\\\]
+        # because to write only two slashes it would have to be r'[\\]' which cant be done directly in hte grammar so it had to be in string form
+        #this way reading [\\] will be interpreted correctly instead of giving an error like it used to
+        if (not mobj):
+            # this is a failure! nice to register!
+            self.failure.update({rulename: {'startpos': j, 'text': self.tokens[rulename]['errortext']}})
+            return []
+        return [{'tree': Tree(rulename, [mobj.group()], j, j + mobj.end()), 'startpos': j, 'endpos': j + mobj.end()}]
+
+    def anonTerm(self, term, j):
+        """
+        #Changed by Daniel: added this whole method.
+        Anonymous term to allow for direct terminals in rules
+        (write 'Foo' directly instead of having to deine a FOO token)
+        """
+        qt = '\''
+        name = qt + term + qt
+        if (j >= len(self.input)):
+            self.failure.update({ name : {'startpos': j, 'text': name}})
+            return []
+
+        mobj = re.match(term, self.input[j:])
+        if (not mobj):
+            # this is a failure! nice to register!
+            self.failure.update({ name : {'startpos': j, 'text': name }})
+            return []
+        return [{'tree': Tree(name , [mobj.group()], j, j + mobj.end()), 'startpos': j, 'endpos': j + mobj.end()}]
+
+    def many(self, rulename, ls, j):
+
+        rule_i = ls[0]
+        if (isinstance(rule_i, list)):
+            results = self.eval_body('*', rule_i, j)
+        else:
+            results = self.applyrule(rule_i, j)
+
+        if (results == []):
+            return [{'tree': None, 'startpos': j, 'endpos': j}]
+
+        seq = ['.'] + ls + [['*'] + ls]
+
+        results = self.eval_body('*', seq, j)
+        overall_results = []
+        for r in results:
+            if (r['tree']):
+                if (len(r['tree'].tail) > 1):
+                    left = r['tree'].tail[0]
+                    right = r['tree'].tail[1].tail
+                    r['tree'].tail = [left] + right
+                overall_results.append(r)
+
+
+        return overall_results
+
+    def more(self, rulename, ls, j):
+
+        rule_i = ls[0]
+        if (isinstance(rule_i, list)):
+            results = self.eval_body('+', rule_i, j)
+        else:
+            results = self.applyrule(rule_i, j)
+
+        if (results == []):
+            return []
+
+        seq = ['.'] + ls + [['*'] + ls]
+
+        results = self.eval_body('+', seq, j)
+        overall_results = []
+        for r in results:
+            if (r['tree']):
+                if (len(r['tree'].tail) > 1):
+                    left = r['tree'].tail[0]
+                    right = r['tree'].tail[1].tail
+                    r['tree'].tail = [left] + right
+                overall_results.append(r)
+
+        return overall_results
+
+    def opt(self, rulename, ls, j):
+        if (j >= len(self.input)):
+            errortext = ''
+            if (rulename in self.rules and 'errortext' in self.rules[rulename]):
+                errortext = self.rules[rulename]['errortext']
+            else:
+                for item in ls:
+                    if ((not isinstance(item[1:], list)) and item[1:] in self.rules):
+                        errortext = self.rules[item[1:]]['errortext']
+            self.failure.update({rulename: {'startpos': j, 'text': errortext}})
+            return [{'tree': None, 'startpos': j, 'endpos': j}]
+
+        results = []
+        rule_i = ls[0]
+        if (isinstance(rule_i, list)):
+            results = self.eval_body('?', rule_i, j)
+        else:
+            results = self.applyrule(rule_i, j)
+
+        if (not results == []):
+            return results
+
+        # empty case
+        return [{'tree': None, 'startpos': j, 'endpos': j}]
+
+    def card(self, rulename, cardrule, ls, j):
+        count = 0
+        delta = 1
+        #  a# a#(-1) #indent, #(-1)indent
+        group = re.match('\((?P<delta>[-+]?\d+)\)(?P<rule>\S+)',cardrule)
+
+        if(group):
+            cardrule = group.group('rule')
+            delta = int(group.group('delta'))
+
+        if (not cardrule in self.countcard):
+            count = delta
+            self.countcard.update({cardrule: {j: count}})
+        else:
+            if not j in self.countcard[cardrule]:  # # if we already know the count for j, then ignore..
+                d = self.countcard[cardrule]
+                lastcount = 0
+                for i in range(0, j):
+                    if i in d:
+                        lastcount = d[i]
+                count = lastcount + delta
+                d.update({j: count})
+            else:
+                count = self.countcard[cardrule][j]
+
+        results = []
+        rule_i = '@' + cardrule
+        if(count == 0):
+            results = [{'tree': None, 'startpos': j, 'endpos': j}]
+        else:
+            for i in range(0, count):
+                if (results == []):
+                    if (isinstance(rule_i, list)):
+                        newresults = self.eval_body(rulename, rule_i, j)
+                    else:
+                        newresults = self.applyrule(rule_i, j)
+                    if (newresults == []):
+                        del self.countcard[cardrule][j]
+                        return []
+                    newresults = self.merge(rulename, newresults, {'startpos': j, 'endpos': j})
+                else:
+                    for elem_p in results:
+                        if (isinstance(rule_i, list)):
+                            newresults = self.eval_body(rulename, rule_i, elem_p['endpos'])
+                        else:
+                            newresults = self.applyrule(rule_i, elem_p['endpos'])
+                        if (newresults == []):
+                            del self.countcard[cardrule][j]
+                            return []
+                        newresults = self.merge(rulename, newresults, elem_p)
+                results = newresults
+
+        for rule_i in ls:
+            for elem_p in results:
+                if (isinstance(rule_i, list)):
+                    newresults = self.eval_body(rulename, rule_i, elem_p['endpos'])
+                else:
+                    newresults = self.applyrule(rule_i, elem_p['endpos'])
+                if (newresults == []):
+                    del self.countcard[cardrule][j]
+                    return []
+                newresults = self.merge(rulename, newresults, elem_p)
+                results = newresults
+
+        del self.countcard[cardrule][j]
+        return results
+
+    def seq(self, rulename, ls, j):
+        #
+        results = []
+        for rule_i in ls:
+            if (results == []):
+                if (isinstance(rule_i, list)):
+                    newresults = self.eval_body('.', rule_i, j)
+                else:
+                    newresults = self.applyrule(rule_i, j)
+                if (newresults == []):
+                    return []
+                newresults = self.merge('.', newresults, {'startpos': j, 'endpos': j})
+            else:
+                for elem_p in results:
+                    if (isinstance(rule_i, list)):
+                        newresults = self.eval_body('.', rule_i, elem_p['endpos'])
+                    else:
+                        newresults = self.applyrule(rule_i, elem_p['endpos'])
+                    if (newresults == []):
+                        return []
+                    newresults = self.merge('.', newresults, elem_p)
+            results = newresults
+        return results
+
+    def merge(self, rulename, newres, elem_p):
+        # Brief: tail of each new tree needs to be prepended with tail of the previous tree
+        # rulename: becomes the head of each tree in the returned list
+        # newres: may have more than one tree in case of alt operator: 'x' ('a' | 'b') 'y'
+        #         tail of each new tree needs to be prepended with tail of previous tree
+        # Returns same list as eval: [{'tree':Tree(head=rulename, tail=[...], startpos=j, endpos=x), 'startpos':j, 'endpos':x}]
+        results = []
+        for elem_n in newres:
+            tail = []
+            if ('tree' in elem_p and elem_p['tree']):
+                tail += elem_p['tree'].tail
+            if ('tree' in elem_n and elem_n['tree']):
+                tail.append(elem_n['tree'])
+            value = {'tree': Tree(rulename, tail, elem_p['startpos'], elem_n['endpos']), 'startpos': elem_p['startpos'],
+                     'endpos': elem_n['endpos']}
+            results += [value]
+        return results
+
+    def alt(self, rulename, ls, j):
+        # Evaluates all alternatives using eval_body or applyrule
+        # Returns same list as eval: [{'tree':Tree(head=rulename, tail=[...], startpos=j, endpos=x), 'startpos':j, 'endpos':x}]
+        overall_results = []
+        results = [] # TODO: remove this variable as it's never used
+        for rule_i in ls:
+            if (isinstance(rule_i, list)):
+                newresults = self.eval_body('|', rule_i, j)
+            else:
+                newresults = self.applyrule(rule_i, j)
+            overall_results += newresults
+
+        return overall_results
+
+    class PositionPostProcessor(object):
+        """
+        This post processor changes absolute position (place in the parsed string )to a line, column position
+        added by Daniel
+        """
+        """
+        efficiency note:
+        how effective is this. this might be slowing things down quit a bit having to calculate that for everything
+        1) an alternative would be use the method only for the leaves, and that traverse the tree bottom up to  create
+        the interval using the left most and right most children of each subtree. but since tat involves extra tree
+        traversal that might not help that much.
+
+        2) another thing that might improve efficiency is to create change the position calculating method:
+        create one that doesnt scan the whole text for new line each time we calculate a position,
+        but creates a table of them the first time.
+        we can calculate the line by returning the index in the table of the the new line the closest to the given
+        position and the column is the difference between the position of that newline and the column (maybe + or - 1,
+        check that)
+        in case this method doesn't slow things down too much ignore this
+        """
+        def __init__(self, method):
+            self.calcPosMethod = method
+
+        def inner_visit(self,tree):
+            startDic = self.calcPosMethod(tree.startpos)
+            endDic = self.calcPosMethod(tree.endpos)
+            tree.startpos = Position(startDic["line"], startDic["column"])
+            tree.endpos =  Position(endDic["line"], endDic["column"])
+            for item in tree.tail:
+                if (isinstance(item, Tree)):
+                    self.inner_visit(item)
+
+        def visit(self, tree):
+            if tree:
+                self.inner_visit(tree)
+            return tree
+
+
+    class DefaultPrinter(object):
+        def __init__(self, output='console'):
+            self.outputStream = ''
+            self.output = output
+
+        def inner_visit(self, tree):
+            for item in tree.tail:
+                if (isinstance(item, Tree)):
+                    self.inner_visit(item)
+                else:
+                    self.outputStream += item
+
+        def visit(self, tree):
+            self.inner_visit(tree)
+            if (self.output == 'console'):
+                print self.outputStream
+
+    class PrettyPrinter(object):
+        def __init__(self, output='console'):
+            self.outputStream = ''
+            self.output = output
+            self.tabcount = -1
+
+        def tab(self):
+            tabspace = ''
+            for i in range(0, self.tabcount):
+                tabspace += '    '
+            return tabspace
+
+        def inner_visit(self, tree):
+            self.tabcount += 1
+            self.outputStream += self.tab()
+            self.outputStream += 'node ' + tree.head + ':\n'
+            for item in tree.tail:
+                if (isinstance(item, Tree)):
+                    self.inner_visit(item)
+                else:
+                    self.tabcount += 1
+                    self.outputStream += self.tab() + item + ' @' + str(tree.startpos) + ' to ' + str(
+                        tree.endpos) + ' \n'
+                    self.tabcount -= 1
+            self.tabcount -= 1
+
+        def visit(self, tree):
+            self.inner_visit(tree)
+            if (self.output == 'console'):
+                print self.outputStream
+
+class IgnorePostProcessor(object):
+    def __init__(self, rules, tokens):
+        self.rules = rules
+        self.tokens = tokens
+
+    def inner_visit(self, tree):
+        results = []
+        if (isinstance(tree, Tree)):
+            if (self.isHidden(tree.head)):
+                for item in tree.tail:
+                    ivlist = []
+                    ivresult = self.inner_visit(item)
+                    for elem in ivresult:
+                        if (isinstance(elem, Tree)):
+                            ivlist += [elem]
+                    results += ivlist
+            else:
+                tlist = []
+                for item in tree.tail:
+                    tlist += self.inner_visit(item)
+                tree.tail = tlist
+                results += [tree]
+            return results
+
+        return [tree]
+
+    def visit(self, tree):
+        # start cannot be hidden
+        tlist = []
+        for item in tree.tail:
+            tlist += self.inner_visit(item)
+        tree.tail = tlist
+        return tree
+
+    def isHidden(self, head):
+        if (head == '*' or head == '+' or head == '?' or head == '|' or head == '.'):
+            return True
+        if (head in self.rules):
+            return 'hidden' in self.rules[head] and self.rules[head]['hidden']
+        elif (head in self.tokens): #Changed by Daniel: added elif condition and return false otherwise, need for anon tokens
+            return 'hidden' in self.tokens[head] and self.tokens[head]['hidden']
+        else:
+            return False
+

+ 93 - 0
interface/HUTN/hutn_compiler/linker.py

@@ -0,0 +1,93 @@
+import sys
+import urllib
+import urllib2
+
+def link(username, objects, fast):
+    # Read out all symbol tables that are to be linked
+    if not fast:
+        definers = {"main": None}
+        for obj in objects:
+            print("[LINK] %s" % (obj))
+            urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": username}))).read()
+            urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"read_symbols"', "username": username}))).read()
+            urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % obj, "username": username}))).read()
+
+            v = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username}))).read()
+            lst = v.rsplit("=", 1)[1]
+            lst = lst.split("\n")
+            for e in lst:
+                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:
+                        if name not in definers:
+                            definers[name] = None
+
+        # 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" % 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:
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '3', "username": username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"read_initializers"', "username": username}))).read()
+        urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "set_input", "element_type": "V", "value": '"%s"' % obj, "username": username}))).read()
+        v = urllib2.urlopen(urllib2.Request("http://localhost:8001/", urllib.urlencode({"op": "get_output", "username": username}))).read()
+        start = str(v.split("&", 1)[0].split("=")[1])
+        initializers.append(start)
+
+    # Bind all initializers together
+    print("[LOAD] %s:main()" % definers["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("http://localhost:8001/", urllib.urlencode({"op": "set_input", "data": json.dumps(commands), "username": username}))).read()
+
+if len(sys.argv) == 1:
+    print("No username defined")
+else:
+    username = sys.argv[1]
+    objects = set(sys.argv[2:])
+    if "--fast" in objects:
+        objects.remove("--fast")
+        fast = True
+    else:
+        fast = False
+
+    if objects:
+        link(username, objects, fast)
+    else:
+        print("No files to link defined")

+ 78 - 0
interface/HUTN/hutn_compiler/loader.py

@@ -0,0 +1,78 @@
+import os
+import sys
+from codecs import open
+
+from grammar_compiler_visitor import GrammarCompilerVisitor
+from hutnparser import Parser
+from meta_grammar import Grammar
+
+
+def dump(obj, nested_level=0, output=sys.stdout):
+    spacing = '   '
+    if type(obj) == dict:
+        print >> output, '%s{' % ((nested_level) * spacing)
+        for k, v in obj.items():
+            if hasattr(v, '__iter__'):
+                print >> output, '%s%s:' % ((nested_level + 1) * spacing, k)
+                dump(v, nested_level + 1, output)
+            else:
+                print >> output, '%s%s: %s' % ((nested_level + 1) * spacing, k, v)
+        print >> output, '%s}' % (nested_level * spacing)
+    elif type(obj) == list:
+        print >> output, '%s[' % ((nested_level) * spacing)
+        for v in obj:
+            if hasattr(v, '__iter__'):
+                dump(v, nested_level + 1, output)
+            else:
+                print >> output, '%s%s' % ((nested_level + 1) * spacing, v)
+        print >> output, '%s]' % ((nested_level) * spacing)
+    else:
+        print >> output, '%s%s' % (nested_level * spacing, obj)
+
+
+def read(n, *args):
+  CUR_PATH = os.path.split(__file__)[0]
+  with open(os.path.join(CUR_PATH, n), *args, encoding='utf-8') as f:
+    return f.read()
+
+def loader(inputfile = './grammars/examples/meta_grammar.g', grammarfile = './grammars/examples/meta_grammar.g'):
+    grammar = Grammar()
+
+#    out1 = open('previous.rules', 'w')
+#    dump(grammar.rules, 0, out1)
+#    out2 = open('previous.tokens', 'w')
+#    dump(grammar.tokens, 0, out2)
+
+    result = parser = Parser(grammar, hide_implicit = True).parse(read(grammarfile))
+    if(not result['status'] == Parser.Constants.Success):
+        print 'not a valid grammar!'
+        print result
+        return
+    
+    tree = result['tree']
+    visitor = GrammarCompilerVisitor()
+    structure = visitor.visit(tree)            
+    grammar.rules = structure['rules']
+    grammar.tokens = structure['tokens']        
+
+#    out3 = open('after.rules', 'w')
+#    dump(structure['rules'], 0, out3)
+#    out4 = open('after.tokens', 'w')
+#    dump(structure['tokens'], 0, out4)
+
+    result = parser = Parser(grammar, hide_implicit = True).parse(read(inputfile))
+    if(not result['status'] == Parser.Constants.Success):
+        print 'not a valid input file!'
+        print result
+        return
+
+    Parser.DefaultPrinter().visit(result['tree'])
+    Parser.PrettyPrinter().visit(result['tree'])
+
+
+if __name__ == "__main__":
+    if(len(sys.argv) == 3):
+        fileName = sys.argv[1]
+        loader(sys.argv[1], sys.argv[2])
+    else:
+        loader()

+ 116 - 0
interface/HUTN/hutn_compiler/meta_grammar.py

@@ -0,0 +1,116 @@
+"""
+Author: Daniel Riegelhaupt
+Date: October 2014
+
+The meta grammar needed by Bruno Barroca's parser to read other grammars.
+Based on his data structure
+"""
+#TODO check escape characters in errortext
+class Grammar(object):
+
+    def __init__(self):
+
+        self.tokens = {
+            #'<token name>' : { 'type': 'token', 'reg': '<token value>' 'errortext': '<human readable error text>'}
+            "LOWER_CASE":  { 'type': 'token', 'reg': r'[a-z_][a-z_0-9]*', 'errortext': 'Lower case characters'},
+            "UPPER_CASE": { 'type': 'token', 'reg': r'[A-Z_][A-Z_0-9]*', 'errortext': 'Upper case characters'},
+            "REGEXP":  { 'type': 'token', 'reg': r'\'(.|\n)*?[^\\]\'', 'errortext': 'Regular expression'},
+            "INT":  { 'type': 'token', 'reg': r'[0-9]*', 'errortext': 'Integers'},
+
+            "IMPLICIT_MOD": { 'type': 'token', 'reg': r'(@Implicit|@Impl)', 'errortext': '@Implicit or @Impl'},
+            "MESSAGE_MOD": { 'type': 'token', 'reg': r'(@Message|@Msg)', 'errortext': '@Message or  @Msg'},
+            "REMOVE_MOD": { 'type': 'token', 'reg': r'(@Remove|@Rm)', 'errortext': '@Remove or  @Rm'},
+            
+            "TOKENS": { 'type': 'token', 'reg': r'tokens'  , 'errortext': 'tokens'},
+            "KEYWORDS": { 'type': 'token', 'reg': r'keywords', 'errortext': 'keywords'},
+            "GRAMMAR": { 'type': 'token', 'reg': r'grammar', 'errortext': 'grammar'},
+            "MAPPER": { 'type': 'token', 'reg': r'mapper', 'errortext': 'mapper'},
+
+            "OPER": { 'type': 'token', 'reg': r'[?*+]', 'errortext': '? or * or +'},
+            "CARD": { 'type': 'token', 'reg': r'#', 'errortext': '#'},
+            "MINUS": { 'type': 'token', 'reg': r'-', 'errortext': '-'},
+            "OR": { 'type': 'token', 'reg': r'\|', 'errortext': '|' },
+            "LPAR": { 'type': 'token', 'reg': r'\(', 'errortext': '(' },
+            "RPAR": { 'type': 'token', 'reg': r'\)', 'errortext': ')' },
+            "SEMICOL": { 'type': 'token', 'reg': r';', 'errortext': ';' },
+            "COMMA": { 'type': 'token', 'reg': r',', 'errortext': ',' },
+            "LCBR": { 'type': 'token', 'reg': r'\{', 'errortext':  '{'},
+            "RCBR": { 'type': 'token', 'reg': r'\}', 'errortext': '}' },
+            "LSBR": { 'type': 'token', 'reg': r'\[', 'errortext':  '['},
+            "RSBR": { 'type': 'token', 'reg': r'\]', 'errortext': ']' },
+            "DOT": { 'type': 'token', 'reg': r'\.', 'errortext':  '.'},
+            "COLON": { 'type': 'token', 'reg': r':', 'errortext': ':'},
+
+            "NEWLINE": { 'type': 'token', 'reg': r'(\r?\n[\t ]*)+'  , 'errortext': 'New Line'},
+            "WS": { 'type': 'token', 'reg': r'[\t \f]+'  , 'errortext': 'White space'},
+            "LINE_CONT": { 'type': 'token', r'reg': '\\[\t \f]*\r?\n', 'errortext': 'Line continuation'},
+            "COMMENT": { 'type': 'token', r'reg': '//[^\n]*', 'errortext': 'Comment'}
+        }
+
+        self.rules = {
+            'start':  {'type': 'prod', 'body':['.', '@grammar', ['?', '@mapper' ]] , 'errortext': 'Top level start',
+                       'interleave': ['?','@implicit'] },
+            
+            'grammar':  {'type': 'prod', 'body': ['.', '$GRAMMAR', '$LCBR', ['*', '@production_rule'], '$RCBR' ], 
+                         'errortext': 'Grammar definition'},
+            
+            'production_rule':  {'type': 'prod', 'body': ['|', '@rule_definition',  '@token_collection' ], 
+                                 'errortext': 'Top level production rule definition'},
+
+            'rule_definition':  {'type': 'prod', 'body':
+                                ['.', '@rule_name', '$COLON', '@rule_right_hand_side', ['*',['|','@message','@remove']],'$SEMICOL' ],
+                                'errortext': 'Production rule definition'},
+
+            'rule_name':  {'type': 'prod', 'body': ['.' , '$LOWER_CASE'], 'errortext': 'Rule name' },
+
+            'rule_right_hand_side': { 'type': 'prod', 'body':  [ '|', '@token_name', '@token_value', '@rule_name',
+                                                         ['.', '$LPAR',  '@rule_right_hand_side', '$RPAR',
+                                                          ['?', '@cardinality']],
+                                                         ['.', '@rule_right_hand_side', '$OR', '@rule_right_hand_side'],
+                                                         ['.', '@rule_right_hand_side', '@rule_right_hand_side'],
+                                                         ['.', '@rule_right_hand_side', '$OPER' ]],
+                                    'errortext':  'Production rule right hand side'},
+
+            'cardinality': { 'type': 'prod', 'body':  ['.', '$CARD', ['?', ['.','$LSBR', ['?', '$MINUS'], '$INT' ,'$RSBR']]],
+                         'errortext': 'Cardinality'},
+
+            'message': { 'type': 'prod', 'body':  ['.', '$MESSAGE_MOD', '@message_value'],
+                         'errortext': 'Error message'},
+
+            'message_value': { 'type': 'prod', 'body':  ['.','$REGEXP'], 'errortext': 'Error message value' },
+
+            'token_collection': { 'type': 'prod', 'body': ['.', '$TOKENS', '$LCBR',
+                                                           ['*',  [ '|', '@token_sub_collection', '@token_definition']],
+                                                           '$RCBR' ],
+                                'errortext': 'Top level token definition' },
+
+            'token_sub_collection': { 'type': 'prod', 'body': [ '.', '@token_collection_category', '$COLON',
+                                                      '@collection_name', '$LCBR',
+                                                      ['*' ,'@token_definition'] ,'$RCBR'],
+                                      'errortext': 'Token collection definition' },
+
+            'token_collection_category': { 'type': 'prod', 'body': ['.', '$KEYWORDS'],
+                                           'errortext':  'Token collection categories: keywords' },
+
+            'collection_name': { 'type': 'prod', 'body': ['.', '$LOWER_CASE'] , 'errortext':  'Token collection name'},
+
+            'token_definition': { 'type': 'prod', 'body': [ '.', '@token_name', '$COLON', '@token_value',
+                                                            ['*',['|','@modifier','@message','@remove']], '$SEMICOL'],
+                                  'errortext':  'Token definition' },
+
+            'token_name': { 'type': 'prod', 'body': ['.', '$UPPER_CASE'] , 'errortext':  'Token name'},
+
+            'token_value': { 'type': 'prod', 'body': ['.', '$REGEXP'] , 'errortext':  'Token value'},
+
+            'modifier': { 'type': 'prod', 'body': ['.', '$IMPLICIT_MOD'] , 'errortext':  'Possible modifiers'},
+
+            'remove': { 'type': 'prod', 'body': ['.', '$REMOVE_MOD'] , 'errortext':  'Possible modifiers'},
+
+            'mapper': { 'type': 'prod', 'body': ['.', '$MAPPER','$LCBR', ['*', '@mapper_content'], '$RCBR'],
+                        'errortext':  'Top level mapper definition'},
+
+            'mapper_content': { 'type': 'prod', 'body': ['.', 'TODO'], 'errortext':  'Content of the mapper' },
+
+            'implicit': {'type': 'prod', 'body':['*', ['|', '$NEWLINE', '$WS', '$LINE_CONT', '$COMMENT']],
+                         'errortext': 'Implicit'}
+        }

+ 73 - 0
interface/HUTN/hutn_compiler/position.py

@@ -0,0 +1,73 @@
+"""
+Author Daniel Riegelhaupt
+November 2014
+
+A simple position object.
+Needed to be able to search in trees using line and column
+"""
+
+class Position(object):
+    """
+    a position object with the comparison operators implemented so that we can use the position to search
+    for backwards compatibility the operator [] has also been overridden
+    ["line"] or ["row"] will get/set self.line and ["column"] or ["col"] will get or set self.column
+    This is not needed and self.line or column can be accesed directly as well
+    """
+    def __init__(self, line, col):
+        self.line = line
+        self.column = col
+
+    def toDictionary(self):
+        return { 'line': self.line, 'column': self.column}
+
+    def __repr__(self):
+        return  "{'line': " + str(self.line)  +", 'column': " + str(self.column) +"}"
+
+    def __str__(self):
+        #return str({ 'line' : self.line , 'column' : self.column })
+        return "{'line': " + str(self.line)  +", 'column': " + str(self.column) +"}"
+
+    def __eq__(self, other):
+        # ==
+        return ((self.line == other.line) and (self.column == other.column))
+
+    def __lt__(self, other):
+        # <
+        return ((self.line < other.line) or ((self.line == other.line) and (self.column < other.column)))
+
+    def __le__(self, other):
+        # <=
+        return ((self.line < other.line) or ((self.line == other.line) and (self.column <= other.column)))
+
+    def __ne__(self, other):
+        # !=
+        return ((self.line != other.line) or (self.column != other.column))
+
+    def __gt__(self, other):
+        # >
+        return ((self.line > other.line) or ((self.line == other.line) and (self.column > other.column)))
+
+    def __ge__(self, other):
+        # <=
+        return ((self.line > other.line) or ((self.line == other.line) and (self.column >= other.column)))
+
+    def __getitem__(self, item):
+        # varname = position['line']
+        if item == 'line' or item == 'row':
+            return self.line
+        elif item == 'column' or item == 'col':
+            return self.column
+        else:
+            raise AttributeError("'Position' object has no attribute '"+str(item)+"'")
+
+    def __setitem__(self, item, value):
+        # position['line'] = 5
+        if item == 'line' or item == 'row':
+            self.line = value
+        elif item == 'column' or item == 'col':
+            self.column =value
+        else:
+            raise AttributeError("'Position' object has no attribute '"+str(item)+"'")
+
+    def deepcopy(self):
+        pass

+ 0 - 0
interface/HUTN/hutn_compiler/prettyprint_visitor.py


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików