Browse Source

First draft to allow for multiple tasks in DEVS model

Yentl Van Tendeloo 7 years ago
parent
commit
fcc6ca46bb

BIN
bootstrap/bootstrap.m.gz


+ 22 - 11
bootstrap/compiler.alc

@@ -21,21 +21,32 @@ Element function generic_compile(code : String, port : String):
 		return read_root()!
 		return read_root()!
 
 
 Element function compile_code(code : String):
 Element function compile_code(code : String):
-	String port
-	port = ""
-	while (port == ""):
-		port = comm_connect("compiler")
+	if (code == "__LOCAL__"):
+		Element list
+		Integer length
 
 
-	comm_set(port, "code")
+		list = list_create()
+		length = input()
 
 
-	Element list
-	list = generic_compile(code, port)
+		while (list_len(list) < length):
+			list_append(list, input())
+		
+		return construct_function_list(list)!
+	else:
+		String port
+		port = ""
+		while (port == ""):
+			port = comm_connect("compiler")
 
 
-	if (element_eq(list, read_root())):
-		return read_root()!
+		comm_set(port, "code")
 
 
-	else:
-		return construct_function_list(list)!
+		Element list
+		list = generic_compile(code, port)
+
+		if (element_eq(list, read_root())):
+			return read_root()!
+		else:
+			return construct_function_list(list)!
 
 
 Element function compile_model(code : String, metamodel : Element):
 Element function compile_model(code : String, metamodel : Element):
 	if (code == "__LOCAL__"):
 	if (code == "__LOCAL__"):

+ 2 - 1
bootstrap/core_algorithm.alc

@@ -2434,7 +2434,8 @@ Void function user_function_skip_init(user_id : String):
 			return !
 			return !
 		elif (cmd == "user_logout"):
 		elif (cmd == "user_logout"):
 			// TODO
 			// TODO
-			cmd = "FAIL"
+			output("Success")
+			return !
 		elif (cmd == "exit"):
 		elif (cmd == "exit"):
 			// Exit by actually removing the user and decoupling it from all of its models
 			// Exit by actually removing the user and decoupling it from all of its models
 			// Restarting with the same user name will NOT grant you access to anything of the previous user with that same name
 			// Restarting with the same user name will NOT grant you access to anything of the previous user with that same name

+ 1 - 0
integration/test_powerwindow.py

@@ -113,6 +113,7 @@ class TestPowerWindow(unittest.TestCase):
         if called != 6:
         if called != 6:
             print(called)
             print(called)
             raise Exception("Not executed sufficiently:" + str(called))
             raise Exception("Not executed sufficiently:" + str(called))
+        user_logout()
 
 
     @slow
     @slow
     def test_process_powerwindow_debug(self):
     def test_process_powerwindow_debug(self):

+ 109 - 19
model/model.py

@@ -1,5 +1,6 @@
 import sys
 import sys
 import time
 import time
+import uuid
 sys.path.append("kernel/")
 sys.path.append("kernel/")
 sys.path.append("state/")
 sys.path.append("state/")
 sys.path.append("interface/HUTN")
 sys.path.append("interface/HUTN")
@@ -338,7 +339,7 @@ class ModelverseKernel(AtomicDEVS):
             outputs[self.to_mvs] = [self.state.commands]
             outputs[self.to_mvs] = [self.state.commands]
 
 
         if self.state.mvk and self.state.mvk.returnvalue is not None:
         if self.state.mvk and self.state.mvk.returnvalue is not None:
-            outputs[self.to_mvi] = [self.state.mvk.returnvalue]
+            outputs[self.to_mvi] = [(self.state.current_task, self.state.mvk.returnvalue)]
 
 
         return outputs
         return outputs
 
 
@@ -355,16 +356,24 @@ class ModelverseKernel(AtomicDEVS):
 class MvIState():
 class MvIState():
     def __init__(self):
     def __init__(self):
         self.operations = []
         self.operations = []
-        self.output = []
-        self.processing = []
-        self.init = True
+        self.additional_operations = []
+        self.keyed_operations = {}
+        self.output = {}
+        self.allow_progress = True
+        self.blocked = True
         self.finished = False
         self.finished = False
+        self.send_operations = []
 
 
 class ModelverseInterface(AtomicDEVS):
 class ModelverseInterface(AtomicDEVS):
-    def __init__(self, taskname, operations, finish_on):
+    def __init__(self, taskname, operations, finish_on, additional_operations=[], keyed_operations={}):
         AtomicDEVS.__init__(self, "MvI_%s" % taskname)
         AtomicDEVS.__init__(self, "MvI_%s" % taskname)
         self.state = MvIState()
         self.state = MvIState()
+        if taskname == "task_manager":
+            self.state.blocked = False
         self.state.operations = operations
         self.state.operations = operations
+        self.state.additional_operations = additional_operations
+        self.state.keyed_operations = keyed_operations
+        self.state.create_additional_task = False
         self.taskname = taskname
         self.taskname = taskname
         self.finish_on = finish_on
         self.finish_on = finish_on
 
 
@@ -372,31 +381,90 @@ class ModelverseInterface(AtomicDEVS):
         self.from_mvk = self.addInPort("from_MvK")
         self.from_mvk = self.addInPort("from_MvK")
 
 
     def intTransition(self):
     def intTransition(self):
-        self.state.init = False
-        self.state.operations = []
+        self.state.create_additional_task = False
+        if self.state.allow_progress:
+            self.state.operations.pop(0)
+        elif not self.state.allow_progress:
+            self.state.send_operations.pop(0)
+
+        self.state.blocked = True
         return self.state
         return self.state
 
 
     def extTransition(self, inputs):
     def extTransition(self, inputs):
         for inp in inputs[self.from_mvk]:
         for inp in inputs[self.from_mvk]:
-            self.state.output.append(inp)
-            if inp == self.finish_on:
+            print("Got input: " + str(inp))
+            self.state.blocked = False
+
+            self.state.output.setdefault(inp[0], []).append(inp[1])
+            if inp[0] == self.taskname and inp[1] == self.finish_on:
                 self.state.finished = True
                 self.state.finished = True
-        print("Event history: " + str(self.state.output))
+            elif inp[0] == self.taskname and self.state.operations[0] is None:
+                # We have to block for now, and modify a model first...
+                print("Blocking for now...")
+                self.state.allow_progress = False
+                prev_output = self.state.output[inp[0]][-1]
+                if prev_output.startswith("Please edit this model before sending next input: "):
+                    _, model_name = prev_output.split("Please edit this model before sending next input: ", 1)
+                    self.state.do_additional_operations = True
+                    self.state.send_operations = [[], ["admin"], ["admin"], [], ["model_modify"], [model_name], ["formalisms/SimpleClassDiagrams"]] + self.state.additional_operations[0] + [["exit"]]
+                    self.state.additional_taskname = str(uuid.uuid4())
+                    print("Modifying model " + str(model_name))
+                    print("On taskname " + str(self.state.additional_taskname))
+                    self.state.create_additional_task = True
+                    self.state.had_key = None
+                elif prev_output.startswith("Spawned activity on task: "):
+                    print("Spawned activity")
+                    _, task_name = prev_output.split("Spawned activity on task: ", 1)
+                    self.state.blocked = True
+
+            elif inp[0] != self.taskname:
+                # Got some output on another task
+                if self.state.send_operations == []:
+                    # At the end of these operations, so finish up!
+                    if self.state.had_key is not None:
+                        self.state.keyed_operations.pop(self.state.had_key)
+                        self.state.additional_taskname = self.state.had_key
+                        self.state.additional_operations.insert(0, [])
+                        self.state.send_operations = ["__continue__"]
+                        self.state.had_key = None
+                    else:
+                        self.state.additional_operations.pop(0)
+                        self.state.do_additional_operations = False
+                        self.state.allow_progress = True
+                        self.state.send_operations = None
+                        self.state.operations[0] = []
+                        print("Clear up to the normal task!")
+                elif inp[1].startswith("Please edit this model before sending next input: "):
+                    _, model_name = inp[1].split("Please edit this model before sending next input: ", 1)
+                    self.state.do_additional_operations = True
+                    self.state.send_operations = [[], ["admin"], ["admin"], [], ["model_modify"], [model_name], ["formalisms/SimpleClassDiagrams"]] + self.state.keyed_operations[inp[0]] + [["exit"]]
+                    self.state.additional_taskname = str(uuid.uuid4())
+                    print("Modifying model " + str(model_name))
+                    print("On taskname " + str(self.state.additional_taskname))
+                    self.state.create_additional_task = True
+                    self.state.had_key = inp[0]
+
         return self.state
         return self.state
 
 
     def outputFnc(self):
     def outputFnc(self):
-        if self.state.operations:
-            return {self.to_mvk: [(self.taskname, self.state.operations)]}
+        if self.state.allow_progress and self.state.operations:
+            print("REQUEST: " + str(self.state.operations[0]))
+            return {self.to_mvk: [(self.taskname, self.state.operations[0])]}
+        elif not self.state.allow_progress and self.state.send_operations:
+            outp = []
+            if self.state.create_additional_task:
+                outp.append(('task_manager', [self.state.additional_taskname]))
+            outp.append((self.state.additional_taskname, self.state.send_operations[0]))
+            print("REQUEST special: " + str(outp))
+            return {self.to_mvk: outp}
         else:
         else:
             return {}
             return {}
 
 
     def timeAdvance(self):
     def timeAdvance(self):
-        if self.state.init:
-            return 0
-        elif self.state.processing:
-            return 0
-        else:
+        if self.state.blocked:
             return float("inf")
             return float("inf")
+        else:
+            return 0.0
 
 
 class NetworkState(object):
 class NetworkState(object):
     def __init__(self):
     def __init__(self):
@@ -444,6 +512,8 @@ class System(CoupledDEVS):
     def __init__(self,
     def __init__(self,
                 taskname,
                 taskname,
                 operations,
                 operations,
+                mvi_additional,
+                mvi_keyed,
                 finish_on,
                 finish_on,
                 rule_generation,
                 rule_generation,
                 time_per_phase,
                 time_per_phase,
@@ -476,13 +546,15 @@ class System(CoupledDEVS):
 
 
         self.mvi_manager = self.addSubModel(ModelverseInterface(\
         self.mvi_manager = self.addSubModel(ModelverseInterface(\
                             taskname            = "task_manager",
                             taskname            = "task_manager",
-                            operations          = [taskname],
+                            operations          = [[taskname]],
                             finish_on           = None,
                             finish_on           = None,
                         ))
                         ))
         self.mvi = self.addSubModel(ModelverseInterface(\
         self.mvi = self.addSubModel(ModelverseInterface(\
                             taskname            = taskname,
                             taskname            = taskname,
                             operations          = operations,
                             operations          = operations,
                             finish_on           = finish_on,
                             finish_on           = finish_on,
+                            additional_operations = mvi_additional,
+                            keyed_operations    = mvi_keyed,
                         ))
                         ))
         self.mvk = self.addSubModel(ModelverseKernel(\
         self.mvk = self.addSubModel(ModelverseKernel(\
                             time_per_phase     = time_per_phase,
                             time_per_phase     = time_per_phase,
@@ -540,13 +612,31 @@ class System(CoupledDEVS):
 
 
 taskname = "test_task"
 taskname = "test_task"
 
 
-operations = ["admin", "admin", "model_add", "formalisms/SimpleClassDiagrams", "formalisms/PN"] + compile_model("models/petrinets.mvc") + ["model_list", "formalisms", "echo", "FINISHED"]
+operations = json.loads(open("model/operations", 'r').read())
+additional_operations = [[], # revise_req
+                         [], # revise_environment
+                         [], # revise_plant
+                         [], # revise_control
+                         [], # revise_query
+                         [], # revise_architecture
+                         [], # make_initial_models
+                         [["instantiate_edge", "Association", "PLANT2EPN_link", "PW_Plant/State", "Encapsulated_PetriNet/Place"], ["instantiate_edge", "Association", "PLANT2EPN_tlink", "PW_Plant/Transition", "Encapsulated_PetriNet/Transition"]], # plant_to_EPN
+                         [["instantiate_edge", "Association", "CTRL2EPN_link", "PW_Control/State", "Encapsulated_PetriNet/Place"], ["instantiate_edge", "Association", "CTRL2EPN_tlink", "PW_Control/Transition", "Encapsulated_PetriNet/Transition"]], # control_to_EPN
+                         [["instantiate_edge", "Association", "ENV2EPN_link", "PW_Environment/Event", "Encapsulated_PetriNet/Place"]], # environment_to_EPN
+                         [["instantiate_edge", "Association", "EPN2PN_place_link", "Encapsulated_PetriNet/Place", "PetriNet/Place"], ["instantiate_edge", "Association", "EPN2PN_transition_link", "Encapsulated_PetriNet/Transition", "PetriNet/Transition"]], # EPN_to_PN
+                         [], # reachability
+                         [], # bfs
+                         [], # merge
+                        ]
+keyed_operations = {}
 finish_on = "FINISHED"
 finish_on = "FINISHED"
 
 
 args = {
 args = {
         "taskname":             taskname,
         "taskname":             taskname,
         "operations":           operations,
         "operations":           operations,
         "finish_on":            finish_on,
         "finish_on":            finish_on,
+        "mvi_additional":       additional_operations,
+        "mvi_keyed":            keyed_operations,
         "mvi2mvk_latency":      0.0000001,
         "mvi2mvk_latency":      0.0000001,
         "mvi2mvk_bandwidth":    50000000000,
         "mvi2mvk_bandwidth":    50000000000,
         "mvk2mvs_latency":      0.0000001,
         "mvk2mvs_latency":      0.0000001,

+ 22 - 7
wrappers/classes/modelverse.xml

@@ -11,8 +11,7 @@
             self.current_ID = action["ID"]
             self.current_ID = action["ID"]
             self.action_name = action["name"]
             self.action_name = action["name"]
         </body>
         </body>
-    </method>
-
+    </method> 
     <method name="dict_to_list">
     <method name="dict_to_list">
         <parameter name="d"/>
         <parameter name="d"/>
         <body>
         <body>
@@ -97,6 +96,7 @@
             self.registered_metamodel = {}
             self.registered_metamodel = {}
             self.inputs = {}
             self.inputs = {}
             self.finish_output_thread = False
             self.finish_output_thread = False
+            self.input_log = []
         </body>
         </body>
     </constructor>
     </constructor>
 
 
@@ -144,6 +144,9 @@
                             <parameter expr='urllib.urlencode({"op": "set_input", "data": json.dumps(value), "taskname": self.taskname})'/>
                             <parameter expr='urllib.urlencode({"op": "set_input", "data": json.dumps(value), "taskname": self.taskname})'/>
                             <parameter expr='None'/>
                             <parameter expr='None'/>
                         </raise>
                         </raise>
+                        <script>
+                            self.input_log.append(value)
+                        </script>
                     </transition>
                     </transition>
 
 
                     <transition event="request" cond="not isinstance(value, type([]))" target=".">
                     <transition event="request" cond="not isinstance(value, type([]))" target=".">
@@ -152,6 +155,9 @@
                             <parameter expr='urllib.urlencode({"op": "set_input", "value": json.dumps(value), "taskname": self.taskname})'/>
                             <parameter expr='urllib.urlencode({"op": "set_input", "value": json.dumps(value), "taskname": self.taskname})'/>
                             <parameter expr='None'/>
                             <parameter expr='None'/>
                         </raise>
                         </raise>
+                        <script>
+                            self.input_log.append([value])
+                        </script>
                     </transition>
                     </transition>
 
 
                     <transition event="request_raw" target=".">
                     <transition event="request_raw" target=".">
@@ -338,7 +344,7 @@
                         <state id="send_metadata">
                         <state id="send_metadata">
                             <onentry>
                             <onentry>
                                 <raise event="request">
                                 <raise event="request">
-                                    <parameter expr="['model_add', self.parameters[1], self.parameters[0], self.parameters[2]]"/>
+                                    <parameter expr="['model_add', self.parameters[1], self.parameters[0]] + ([self.parameters[2]] if not COMPILE_LOCAL else compile_model(self.parameters[2]))"/>
                                 </raise>
                                 </raise>
                             </onentry>
                             </onentry>
 
 
@@ -446,7 +452,7 @@
                         <state id="send_model">
                         <state id="send_model">
                             <onentry>
                             <onentry>
                                 <raise event="request">
                                 <raise event="request">
-                                    <parameter expr="self.parameters[1]"/>
+                                    <parameter expr="self.parameters[1] if not COMPILE_LOCAL else compile_model(self.parameters[1])"/>
                                 </raise>
                                 </raise>
                             </onentry>
                             </onentry>
 
 
@@ -474,6 +480,10 @@
 
 
                     <state id="user_logout">
                     <state id="user_logout">
                         <onentry>
                         <onentry>
+                            <script>
+                                import json
+                                print(json.dumps(self.input_log))
+                            </script>
                             <raise event="request">
                             <raise event="request">
                                 <parameter expr="'user_logout'"/>
                                 <parameter expr="'user_logout'"/>
                             </raise>
                             </raise>
@@ -600,6 +610,7 @@
                                 <transition cond="self.expect_response_partial('Please edit this model before sending next input: ', pop=False)" target="../wait_for_user">
                                 <transition cond="self.expect_response_partial('Please edit this model before sending next input: ', pop=False)" target="../wait_for_user">
                                     <script>
                                     <script>
                                         model = self.responses.pop(0).split(": ", 1)[1]
                                         model = self.responses.pop(0).split(": ", 1)[1]
+                                        self.input_log.append(None)
                                     </script>
                                     </script>
                                     <raise event="result">
                                     <raise event="result">
                                         <parameter expr="model"/>
                                         <parameter expr="model"/>
@@ -607,11 +618,12 @@
                                 </transition>
                                 </transition>
 
 
                                 <transition cond="self.expect_response('Waiting for code constructors...')" target="../upload_changes">
                                 <transition cond="self.expect_response('Waiting for code constructors...')" target="../upload_changes">
+                                    <!-- TODO Is this ever executed? -->
                                     <raise event="result">
                                     <raise event="result">
                                         <parameter expr="None"/>
                                         <parameter expr="None"/>
                                     </raise>
                                     </raise>
                                     <raise event="request">
                                     <raise event="request">
-                                        <parameter expr="self.parameters[3]"/>
+                                        <parameter expr="self.parameters[3] if not COMPILE_LOCAL else compile_code(self.parameters[3])"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
                             </state>
                             </state>
@@ -630,13 +642,13 @@
                             <state id="upload_changes">
                             <state id="upload_changes">
                                 <transition cond="self.expect_response('Waiting for code constructors...')" target=".">
                                 <transition cond="self.expect_response('Waiting for code constructors...')" target=".">
                                     <raise event="request">
                                     <raise event="request">
-                                        <parameter expr="self.parameters[3]"/>
+                                        <parameter expr="self.parameters[3] if not COMPILE_LOCAL else compile_code(self.parameters[3])"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
 
 
                                 <transition cond="self.expect_response('Waiting for model constructors...')" target=".">
                                 <transition cond="self.expect_response('Waiting for model constructors...')" target=".">
                                     <raise event="request">
                                     <raise event="request">
-                                        <parameter expr="self.parameters[3]"/>
+                                        <parameter expr="self.parameters[3] if not COMPILE_LOCAL else compile_model(self.parameters[3])"/>
                                     </raise>
                                     </raise>
                                 </transition>
                                 </transition>
 
 
@@ -1438,6 +1450,9 @@
                                     <raise event="result">
                                     <raise event="result">
                                         <parameter expr="self.responses.pop(0).split(': ')[1]"/>
                                         <parameter expr="self.responses.pop(0).split(': ')[1]"/>
                                     </raise>
                                     </raise>
+                                    <script>
+                                        self.input_log.append(None)
+                                    </script>
                                 </transition>
                                 </transition>
 
 
                                 <transition cond="None in self.inputs and self.inputs[None]" target="../../../history">
                                 <transition cond="None in self.inputs and self.inputs[None]" target="../../../history">

+ 45 - 6
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
 
-Date:   Mon Dec 18 13:49:08 2017
+Date:   Tue Dec 19 14:25:12 2017
 
 
 Model author: Yentl Van Tendeloo
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server
@@ -19,6 +19,38 @@ import urllib
 import json
 import json
 import sys
 import sys
 
 
+COMPILE_LOCAL = True
+if COMPILE_LOCAL:
+    sys.path.append("interface/HUTN")
+    from hutn_compiler.compiler import main as do_compile
+
+    def clean_code(code):
+        if code == "":
+            return code
+
+        code_fragments = code.split("\n")
+        code_fragments = [i.rstrip() for i in code_fragments if i.strip() != ""]
+        code_fragments = [i.replace("    ", "\t") for i in code_fragments]
+        initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
+        code_fragments = [i[initial_tabs:] for i in code_fragments]
+        code_fragments.append("")
+        code = "\n".join(code_fragments)
+        return code.encode('ascii', 'replace')
+
+    def compile_model(model):
+        temp_file = ".model_%s" % str(uuid.uuid4())
+        with open(temp_file, 'w') as f:
+            f.write(model)
+        compiled = do_compile(temp_file, "interface/HUTN/grammars/modelling.g", "M")
+        return ["__LOCAL__"] + compiled
+
+    def compile_code(code):
+        temp_file = ".code_%s" % str(uuid.uuid4())
+        with open(temp_file, 'w') as f:
+            f.write(code)
+        compiled = do_compile(temp_file, "interface/HUTN/grammars/actionlanguage.g", "CS")
+        return ["__LOCAL__"] + compiled
+
 # package "MvK Server"
 # package "MvK Server"
 
 
 class Modelverse(RuntimeClassBase):
 class Modelverse(RuntimeClassBase):
@@ -48,6 +80,7 @@ class Modelverse(RuntimeClassBase):
         self.registered_metamodel = {}
         self.registered_metamodel = {}
         self.inputs = {}
         self.inputs = {}
         self.finish_output_thread = False
         self.finish_output_thread = False
+        self.input_log = []
     
     
     def user_defined_destructor(self):
     def user_defined_destructor(self):
         pass
         pass
@@ -1883,7 +1916,7 @@ class Modelverse(RuntimeClassBase):
         self.raiseInternalEvent(Event("request", None, [['model_list', self.parameters[0]]]))
         self.raiseInternalEvent(Event("request", None, [['model_list', self.parameters[0]]]))
     
     
     def _initialized_behaviour_operations_model_add_send_metadata_enter(self):
     def _initialized_behaviour_operations_model_add_send_metadata_enter(self):
-        self.raiseInternalEvent(Event("request", None, [['model_add', self.parameters[1], self.parameters[0], self.parameters[2]]]))
+        self.raiseInternalEvent(Event("request", None, [['model_add', self.parameters[1], self.parameters[0]] + ([self.parameters[2]] if not COMPILE_LOCAL else compile_model(self.parameters[2]))]))
     
     
     def _initialized_behaviour_operations_model_delete_enter(self):
     def _initialized_behaviour_operations_model_delete_enter(self):
         self.raiseInternalEvent(Event("request", None, [['model_delete', self.parameters[0]]]))
         self.raiseInternalEvent(Event("request", None, [['model_delete', self.parameters[0]]]))
@@ -1898,12 +1931,14 @@ class Modelverse(RuntimeClassBase):
         self.raiseInternalEvent(Event("request", None, [['model_overwrite', self.parameters[0], self.registered_metamodel[self.parameters[0]]]]))
         self.raiseInternalEvent(Event("request", None, [['model_overwrite', self.parameters[0], self.registered_metamodel[self.parameters[0]]]]))
     
     
     def _initialized_behaviour_operations_model_overwrite_send_model_enter(self):
     def _initialized_behaviour_operations_model_overwrite_send_model_enter(self):
-        self.raiseInternalEvent(Event("request", None, [self.parameters[1]]))
+        self.raiseInternalEvent(Event("request", None, [self.parameters[1] if not COMPILE_LOCAL else compile_model(self.parameters[1])]))
     
     
     def _initialized_behaviour_operations_disconnect_enter(self):
     def _initialized_behaviour_operations_disconnect_enter(self):
         self.raiseInternalEvent(Event("request", None, ['exit']))
         self.raiseInternalEvent(Event("request", None, ['exit']))
     
     
     def _initialized_behaviour_operations_user_logout_enter(self):
     def _initialized_behaviour_operations_user_logout_enter(self):
+        import json
+        print(json.dumps(self.input_log))
         self.raiseInternalEvent(Event("request", None, ['user_logout']))
         self.raiseInternalEvent(Event("request", None, ['user_logout']))
     
     
     def _initialized_behaviour_operations_user_delete_enter(self):
     def _initialized_behaviour_operations_user_delete_enter(self):
@@ -2272,6 +2307,7 @@ class Modelverse(RuntimeClassBase):
     def _initialized_http_mapper_init_0_exec(self, parameters):
     def _initialized_http_mapper_init_0_exec(self, parameters):
         value = parameters[0]
         value = parameters[0]
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.http_clients[0], Event("HTTP_input", None, [urllib.urlencode({"op": "set_input", "data": json.dumps(value), "taskname": self.taskname}), None])]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.http_clients[0], Event("HTTP_input", None, [urllib.urlencode({"op": "set_input", "data": json.dumps(value), "taskname": self.taskname}), None])]))
+        self.input_log.append(value)
     
     
     def _initialized_http_mapper_init_0_guard(self, parameters):
     def _initialized_http_mapper_init_0_guard(self, parameters):
         value = parameters[0]
         value = parameters[0]
@@ -2280,6 +2316,7 @@ class Modelverse(RuntimeClassBase):
     def _initialized_http_mapper_init_1_exec(self, parameters):
     def _initialized_http_mapper_init_1_exec(self, parameters):
         value = parameters[0]
         value = parameters[0]
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.http_clients[0], Event("HTTP_input", None, [urllib.urlencode({"op": "set_input", "value": json.dumps(value), "taskname": self.taskname}), None])]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.http_clients[0], Event("HTTP_input", None, [urllib.urlencode({"op": "set_input", "value": json.dumps(value), "taskname": self.taskname}), None])]))
+        self.input_log.append([value])
     
     
     def _initialized_http_mapper_init_1_guard(self, parameters):
     def _initialized_http_mapper_init_1_guard(self, parameters):
         value = parameters[0]
         value = parameters[0]
@@ -2510,6 +2547,7 @@ class Modelverse(RuntimeClassBase):
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0_exec(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0_exec(self, parameters):
         model = self.responses.pop(0).split(": ", 1)[1]
         model = self.responses.pop(0).split(": ", 1)[1]
+        self.input_log.append(None)
         self.raiseInternalEvent(Event("result", None, [model]))
         self.raiseInternalEvent(Event("result", None, [model]))
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0_guard(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_0_guard(self, parameters):
@@ -2517,7 +2555,7 @@ class Modelverse(RuntimeClassBase):
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_exec(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_exec(self, parameters):
         self.raiseInternalEvent(Event("result", None, [None]))
         self.raiseInternalEvent(Event("result", None, [None]))
-        self.raiseInternalEvent(Event("request", None, [self.parameters[3]]))
+        self.raiseInternalEvent(Event("request", None, [self.parameters[3] if not COMPILE_LOCAL else compile_code(self.parameters[3])]))
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_guard(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_send_metadata_1_guard(self, parameters):
         return self.expect_response('Waiting for code constructors...')
         return self.expect_response('Waiting for code constructors...')
@@ -2530,13 +2568,13 @@ class Modelverse(RuntimeClassBase):
         return None in self.inputs and self.inputs[None]
         return None in self.inputs and self.inputs[None]
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_0_exec(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_0_exec(self, parameters):
-        self.raiseInternalEvent(Event("request", None, [self.parameters[3]]))
+        self.raiseInternalEvent(Event("request", None, [self.parameters[3] if not COMPILE_LOCAL else compile_code(self.parameters[3])]))
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_0_guard(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_0_guard(self, parameters):
         return self.expect_response('Waiting for code constructors...')
         return self.expect_response('Waiting for code constructors...')
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_1_exec(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_1_exec(self, parameters):
-        self.raiseInternalEvent(Event("request", None, [self.parameters[3]]))
+        self.raiseInternalEvent(Event("request", None, [self.parameters[3] if not COMPILE_LOCAL else compile_model(self.parameters[3])]))
     
     
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_1_guard(self, parameters):
     def _initialized_behaviour_operations_store_on_scripted_transformation_add_upload_changes_1_guard(self, parameters):
         return self.expect_response('Waiting for model constructors...')
         return self.expect_response('Waiting for model constructors...')
@@ -2901,6 +2939,7 @@ class Modelverse(RuntimeClassBase):
     
     
     def _initialized_behaviour_wait_for_action_activity_OP_forwarding_1_exec(self, parameters):
     def _initialized_behaviour_wait_for_action_activity_OP_forwarding_1_exec(self, parameters):
         self.raiseInternalEvent(Event("result", None, [self.responses.pop(0).split(': ')[1]]))
         self.raiseInternalEvent(Event("result", None, [self.responses.pop(0).split(': ')[1]]))
+        self.input_log.append(None)
     
     
     def _initialized_behaviour_wait_for_action_activity_OP_forwarding_1_guard(self, parameters):
     def _initialized_behaviour_wait_for_action_activity_OP_forwarding_1_guard(self, parameters):
         return self.expect_response_partial('Please edit this model before sending next input: ', pop=False)
         return self.expect_response_partial('Please edit this model before sending next input: ', pop=False)

+ 32 - 0
wrappers/modelverse_SCCD.xml

@@ -12,6 +12,38 @@
         import urllib
         import urllib
         import json
         import json
         import sys
         import sys
+
+        COMPILE_LOCAL = True
+        if COMPILE_LOCAL:
+            sys.path.append("interface/HUTN")
+            from hutn_compiler.compiler import main as do_compile
+
+            def clean_code(code):
+                if code == "":
+                    return code
+
+                code_fragments = code.split("\n")
+                code_fragments = [i.rstrip() for i in code_fragments if i.strip() != ""]
+                code_fragments = [i.replace("    ", "\t") for i in code_fragments]
+                initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
+                code_fragments = [i[initial_tabs:] for i in code_fragments]
+                code_fragments.append("")
+                code = "\n".join(code_fragments)
+                return code.encode('ascii', 'replace')
+
+            def compile_model(model):
+                temp_file = ".model_%s" % str(uuid.uuid4())
+                with open(temp_file, 'w') as f:
+                    f.write(model)
+                compiled = do_compile(temp_file, "interface/HUTN/grammars/modelling.g", "M")
+                return ["__LOCAL__"] + compiled
+
+            def compile_code(code):
+                temp_file = ".code_%s" % str(uuid.uuid4())
+                with open(temp_file, 'w') as f:
+                    f.write(code)
+                compiled = do_compile(temp_file, "interface/HUTN/grammars/actionlanguage.g", "CS")
+                return ["__LOCAL__"] + compiled
     </top>
     </top>
 
 
     <inport name="socket_in"/>
     <inport name="socket_in"/>